package com.dxhy.core.job.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.dxhy.api.model.invoice.TDxRecordInvoice;
import com.dxhy.common.constant.CoreConstants;
import com.dxhy.common.service.impl.MpBaseServiceImpl;
import com.dxhy.common.util.ZipUtils;
import com.dxhy.common.utils.CommonUtil;
import com.dxhy.core.job.dao.LqTdxInvoiceFileCoreDao;
import com.dxhy.core.job.dao.TDxRecordInvoiceJobDao;
import com.dxhy.core.job.dao.TDxSaleRecordInvoiceJobDao;
import com.dxhy.core.job.entity.TDxInvoiceFileEntity;
import com.dxhy.core.job.entity.TDxSaleRecordInvoiceJobEntity;
import com.dxhy.core.job.pojo.Authorize;
import com.dxhy.core.job.pojo.BaseQueJson;
import com.dxhy.core.job.pojo.BaseResJson;
import com.dxhy.core.job.pojo.GlobalInfo;
import com.dxhy.core.job.service.TdxInvoiceFileNewService;
import com.dxhy.oss.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;


@Service("tdxInvoiceFileNewService")
@Slf4j
public class TdxInvoiceFileNewServiceImpl
		extends MpBaseServiceImpl<LqTdxInvoiceFileCoreDao, TDxInvoiceFileEntity>
        implements TdxInvoiceFileNewService {
			

	@Resource
	private FileService fileService;

	@Resource
	private TDxRecordInvoiceJobDao tDxRecordInvoiceJobDao;
	@Resource
	private TDxSaleRecordInvoiceJobDao tDxSatleRecordInvoiceJobDao;

	@Autowired
	private LqTdxInvoiceFileCoreDao lqTdxInvoiceFileDao;

	/**
	* @Description 数电发票xml源文件下载
	* @param
	* @param tri 用底账查出来的实体
	 * @param reqMap 请求下载源文件参数
	 * @param jxXxtype	  进项销项类型   01进项票   02销项票
	 * @Return boolean 当请求大企业接口，并返回有文件的情况，返回true，其他均为false
	* @Author wangruwei
	* @Date 2024/4/9 16:27
	**/
	@Override
	public boolean dealXmlSource(TDxRecordInvoice tri, Map<String, String> reqMap, String jxXxtype, String aceId, String aceKey) throws Exception {
		boolean downLoadFileFlag = false;
		//先判断是否已有，有的话，不再保存处理
		TDxInvoiceFileEntity tfileExist = lqTdxInvoiceFileDao.selectOne(new LambdaQueryWrapper<TDxInvoiceFileEntity>().eq(TDxInvoiceFileEntity::getUuid, tri.getUuid())
				.isNotNull(TDxInvoiceFileEntity::getXmlPath)
		);
		if(ObjectUtil.isNotEmpty(tfileExist)){
			log.info("uuid:{}。xml在invoice_file表里已存在，不再重复存",tri.getUuid());
			//更新抵账表xmlFlag
			updateXmlFlag(tri,jxXxtype,"1");
			return downLoadFileFlag;
		}
		//调下载文件接口
		Map<String, Object> requestYwjMap = requestYwjDown(reqMap, aceId, aceKey);
		if("0000".equals(requestYwjMap.get("code"))){
			log.info("有数据流，保存文件");
			String xmlFileName = CommonUtil.getFileName(tri.getUuid());
			String tempXmlFilePath = fileService.getLocalPathDefault() + "/temp_xml/" + xmlFileName + ".xml";
			String tempZipFileName = fileService.getLocalPathDefault() + "/temp_xml/" + tri.getUuid() + ".zip";
			String tempJyZipFileDir = fileService.getLocalPathDefault() + "/temp_xml/" + tri.getUuid();

            HttpResponse response = null;
            try {
				response = (HttpResponse)requestYwjMap.get("HttpResponse");
				long writeSize = response.writeBody(new File(tempZipFileName), null);
				if (writeSize!=-1L) {
					log.info("xml文件下载成功，解压缩");
					ZipUtils.jyZip(tempZipFileName, tempJyZipFileDir);
					File file1 = new File(tempJyZipFileDir);
					File[] files = file1.listFiles();
					for (File f : files) {
						if (f.isFile()) {
							if (f.getName().endsWith("xml")||f.getName().endsWith("XML")) {
								FileUtils.copyFile(f, new File(tempXmlFilePath));
								break;
							}
						}
					}
					log.info("xml文件上传ftp");
					File tempFile = new File(tempXmlFilePath);
					if (tempFile.exists()) {
						// FTP文件存储路径
						String ftpFilePath = CommonUtil.getFtpFilePath(fileService.getPathPrefix(),tri.getGfTaxNo(),xmlFileName);
						log.info("开始上传ftp,ftp存储路径:{}",ftpFilePath);
						fileService.uploadFile(ftpFilePath, tempXmlFilePath);
						log.info("上传ftp完成,更新抵账表、插入发票附件表");

						//更新抵账表xmlFlag
						updateXmlFlag(tri,jxXxtype,"1");
						//保存xml路径至t_dx_invoice_file表
						TDxInvoiceFileEntity tdf = new TDxInvoiceFileEntity();
						tdf.setUuid(tri.getUuid());
						tdf.setXmlPath(ftpFilePath);
						tdf.setCreateTime(new Date());
						TDxInvoiceFileEntity tfile = lqTdxInvoiceFileDao.selectOne(new QueryWrapper<TDxInvoiceFileEntity>().eq("uuid", tri.getUuid()));
						if (tfile == null) {
							lqTdxInvoiceFileDao.insert(tdf);
						} else {
							lqTdxInvoiceFileDao.updateById(tdf);
						}

					}
				}
				//删除临时文件
				log.info("删除临时文件");
				File fileDir = new File(tempJyZipFileDir);
				if (fileDir.exists()) {
					FileUtils.deleteDirectory(fileDir);
				}
				FileUtils.deleteQuietly(new File(tempZipFileName));
				downLoadFileFlag = true;
			} catch (Exception e) {
				log.info("处理xml文件储存失败{}",e);
			} finally {
                if (response != null) {
                    response.close(); // 关闭 HTTP 响应，释放资源
                }
            }

		}else{
			log.info("没有发票文件");
		}
		return downLoadFileFlag;
	}

	/**
	 * @Description 处理源文件下载，xml的保存业务
	 * @param tri
	 * @param reqMap 请求下载源文件参数
	 * @param jxXxtype	  进项销项类型   01进项票   02销项票
	 * @Return boolean 当请求大企业接口，并返回有文件的情况，返回true，其他均为false
	 * @Author wangruwei
	 * @Date 2024/4/9 16:31
	 **/
	@Override
	public boolean dealPdfSource(TDxRecordInvoice tri, Map<String, String> reqMap, String jxXxtype, String aceId, String aceKey) throws Exception {
		boolean downLoadFileFlag = false;
		//先判断是否已有，有的话，不再保存处理
		TDxInvoiceFileEntity tfileExist = lqTdxInvoiceFileDao.selectOne(new LambdaQueryWrapper<TDxInvoiceFileEntity>().eq(TDxInvoiceFileEntity::getUuid, tri.getUuid())
				.isNotNull(TDxInvoiceFileEntity::getPdfPath)
		);
		if(ObjectUtil.isNotEmpty(tfileExist)){
			log.info("uuid:{}。pdf在invoice_file表里已存在，不再重复存",tri.getUuid());
			//更新抵账表xmlFlag
			updateXmlFlag(tri,jxXxtype,"2");
			return downLoadFileFlag;
		}

		//调下载文件接口
		Map<String, Object> requestYwjMap = requestYwjDown(reqMap, aceId, aceKey);
		if("0000".equals(requestYwjMap.get("code"))){
			log.info("有数据流，保存文件");
			String pdfFileName = CommonUtil.getFileNamePdf(tri.getUuid());
			String tempPdfFilePath = fileService.getLocalPathDefault() + "/temp_pdf/" + pdfFileName + ".pdf";
            HttpResponse response = null;
            try {
				//调下载文件接口
				response = (HttpResponse)requestYwjMap.get("HttpResponse");
				long writeSize = response.writeBody(new File(tempPdfFilePath), null);
				if (writeSize!=-1L) {
					log.info("pdf文件下载成功");
					log.info("pdf文件上传ftp");
					File tempFile = new File(tempPdfFilePath);
					if (tempFile.exists()) {
						// FTP文件存储路径
						String ftpFilePath = CommonUtil.getFtpFilePath(fileService.getPathPrefix(),tri.getGfTaxNo(),pdfFileName);
						log.info("开始上传ftp,ftp存储路径:{}",ftpFilePath);
						fileService.uploadFile(ftpFilePath, tempPdfFilePath);
						log.info("上传ftp完成,更新抵账表、插入发票附件表");
						//更新抵账表xmlFlag
						updateXmlFlag(tri,jxXxtype,"2");
						//保存pdf路径至t_dx_invoice_file表
						TDxInvoiceFileEntity tdf = new TDxInvoiceFileEntity();
						tdf.setUuid(tri.getUuid());
						tdf.setPdfPath(ftpFilePath);
						tdf.setCreateTime(new Date());
						TDxInvoiceFileEntity tfile = lqTdxInvoiceFileDao.selectOne(new QueryWrapper<TDxInvoiceFileEntity>().eq("uuid",tri.getUuid()));
						if (tfile == null) {
							lqTdxInvoiceFileDao.insert(tdf);
						} else {
							lqTdxInvoiceFileDao.updateById(tdf);
						}
					}
				}
				//删除临时文件
				log.info("删除临时文件");
				File fileDir = new File(tempPdfFilePath);
				if (fileDir.exists()) {
					FileUtils.deleteQuietly(fileDir);
				}
				FileUtils.deleteQuietly(new File(tempPdfFilePath));
				downLoadFileFlag = true;
			} catch (Exception e) {
				log.info("处理pdf文件储存失败{}",e);
			} finally {
                if (response != null) {
                    response.close(); // 关闭 HTTP 响应，释放资源
                }
            }
		}else{
            log.info("没有发票文件");
        }
		return downLoadFileFlag;
	}

	/**
	 * @Description 处理源文件下载，ofd的保存业务
	 * @param tri
	 * @param reqMap 请求下载源文件参数
	 * @param jxXxtype	  进项销项类型   01进项票   02销项票
	 * @Return boolean 当请求大企业接口，并返回有文件的情况，返回true，其他均为false
	 * @Author wangruwei
	 * @Date 2024/4/9 16:31
	 **/
	@Override
	public boolean dealOfdSource(TDxRecordInvoice tri, Map<String, String> reqMap, String jxXxtype, String aceId, String aceKey) throws Exception {
		boolean downLoadFileFlag = false;
		//先判断是否已有，有的话，不再保存处理
		TDxInvoiceFileEntity tfileExist = lqTdxInvoiceFileDao.selectOne(new LambdaQueryWrapper<TDxInvoiceFileEntity>().eq(TDxInvoiceFileEntity::getUuid, tri.getUuid())
				.isNotNull(TDxInvoiceFileEntity::getOfdPath)
		);
		if(ObjectUtil.isNotEmpty(tfileExist)){
			log.info("uuid:{}。ofd在invoice_file表里已存在，不再重复存",tri.getUuid());
			//更新抵账表xmlFlag
			updateXmlFlag(tri,jxXxtype,"3");
			return downLoadFileFlag;
		}

		//调下载文件接口
		Map<String, Object> requestYwjMap = requestYwjDown(reqMap, aceId, aceKey);
		if("0000".equals(requestYwjMap.get("code"))) {
			log.info("有数据流，保存文件");

			String ofdFileName = CommonUtil.getFileNameOfd(tri.getUuid());
			String tempOfdFilePath = fileService.getLocalPathDefault() + "/temp_ofd/" + ofdFileName + ".ofd";
            HttpResponse response = null;
            try {
				response = (HttpResponse)requestYwjMap.get("HttpResponse");
				long writeSize = response.writeBody(new File(tempOfdFilePath), null);
				if (writeSize!=-1L) {
					log.info("ofd文件下载成功");
					log.info("ofd文件上传ftp");
					File tempFile = new File(tempOfdFilePath);
					if (tempFile.exists()) {
						// FTP文件存储路径
						String ftpFilePath = CommonUtil.getFtpFilePath(fileService.getPathPrefix(),tri.getGfTaxNo(),ofdFileName);
						log.info("开始上传ftp,ftp存储路径:{}",ftpFilePath);
						fileService.uploadFile(ftpFilePath, tempOfdFilePath);
						log.info("上传ftp完成,更新抵账表、插入发票附件表");
						//更新抵账表xmlFlag
						updateXmlFlag(tri,jxXxtype,"3");
						//保存ofd路径至t_dx_invoice_file表
						TDxInvoiceFileEntity tdf = new TDxInvoiceFileEntity();
						tdf.setUuid(tri.getUuid());
						tdf.setOfdPath(ftpFilePath);
						tdf.setCreateTime(new Date());
						TDxInvoiceFileEntity tfile = lqTdxInvoiceFileDao.selectOne(new QueryWrapper<TDxInvoiceFileEntity>().eq("uuid", tri.getUuid()));
						if (tfile == null) {
							lqTdxInvoiceFileDao.insert(tdf);
						} else {
							lqTdxInvoiceFileDao.updateById(tdf);
						}
					}
				}
				//删除临时文件
				log.info("删除临时文件");
				File fileDir = new File(tempOfdFilePath);
				if (fileDir.exists()) {
					FileUtils.deleteQuietly(fileDir);
				}
				FileUtils.deleteQuietly(new File(tempOfdFilePath));
				downLoadFileFlag = true;
			} catch (Exception e) {
				log.info("处理ofd文件储存失败{}",e);
			} finally {
                if (response != null) {
                    response.close(); // 关闭 HTTP 响应，释放资源
                }
            }
		}else{
            log.info("没有发票文件");
        }
		return downLoadFileFlag;
	}

	private void updateXmlFlag(TDxRecordInvoice tri, String jxXxtype,String flag) {

		//更新抵账表
		if("01".equals(jxXxtype)){
			String xmlFlag =  tDxRecordInvoiceJobDao.selectOne(new LambdaQueryWrapper<TDxRecordInvoice>().eq(TDxRecordInvoice::getUuid, tri.getUuid())).getXmlFlag();
			xmlFlag = CommonUtil.addXmlFlag(xmlFlag,flag);
			tDxRecordInvoiceJobDao.update(null, new UpdateWrapper<TDxRecordInvoice>().eq("uuid", tri.getUuid()).set("xml_flag", xmlFlag));
		}
		if("02".equals(jxXxtype)){
			String xmlFlag =  tDxSatleRecordInvoiceJobDao.selectOne(new LambdaQueryWrapper<TDxSaleRecordInvoiceJobEntity>().eq(TDxSaleRecordInvoiceJobEntity::getUuid, tri.getUuid())).getXmlFlag();
			xmlFlag = CommonUtil.addXmlFlag(xmlFlag,flag);
			tDxSatleRecordInvoiceJobDao.update(null, new LambdaUpdateWrapper<TDxSaleRecordInvoiceJobEntity>().eq(TDxSaleRecordInvoiceJobEntity::getUuid, tri.getUuid()).set(TDxSaleRecordInvoiceJobEntity::getXmlFlag, xmlFlag));
		}
	}


    /**
    * @Description 调下载源文件接口
    * @Return void
    * @Author wangruwei
    * @Date 2024/8/6 10:32
    **/
	private static Map<String,Object> requestYwjDown(Map<String, String> reqMap, String aceId, String aceKey) {
		BaseQueJson bqj = new BaseQueJson();
		// 请求通用头
		GlobalInfo globalInfo = new GlobalInfo();
		// 请求通用
		Authorize authorize = new Authorize();
		// 封装参数
		globalInfo.setAppId(CoreConstants.appId);
		globalInfo.setVersion(CoreConstants.version);
		String exchangeId = getDataExchangeId();
		globalInfo.setDataExchangeId(exchangeId);
		globalInfo.setInterfaceCode(CoreConstants.sourceFileGetNew);
		globalInfo.setEnterpriseCode(CoreConstants.enterpriseCode);
		authorize.setAppSecId(aceId);
		String base64Data = Base64.encode(JSONObject.toJSONString(reqMap));
		String appSec = makeAppSec(base64Data, exchangeId, CoreConstants.sourceFileGetNew, aceId, aceKey);
		authorize.setAppSec(appSec);
		bqj.setData(base64Data);
		bqj.setAuthorize(authorize);
		bqj.setGlobalInfo(globalInfo);
		String collectDataStr = JSONObject.toJSONString(bqj);
		log.info("url:" + CoreConstants.invoiceYwjDownUrl);
		log.info("请求参数：" + collectDataStr);
		log.info("发送请求--");
		HttpResponse response = HttpUtil.createPost(CoreConstants.invoiceYwjDownUrl).timeout(600000).body(collectDataStr).executeAsync();

		//log.info("返回参数:{}", response.body());
		// 根据发票类型保存不同实体
		Map<String,Object> result = new HashMap();
		try {
			JSONObject.parseObject(response.body(), BaseResJson.class);
			log.info("调文件下载返回:{},返回长度:{}", response.body(),response.body().length());
			result.put("code", "9999");
		} catch (Exception e) {
			log.info("调文件下载，返回内容不为json。返回长度:{}",response.body().length());
			String contentType = response.header("Content-Type");
			if(contentType.contains("application/octet-stream")){
				log.info("contentType为application/octet-stream，以文件流保存");
				result.put("code", "0000");
				result.put("HttpResponse",response );
			}else{
				log.info("contentType返回{}，不是文件，不做处理。返回:{}",contentType,response.body());
				result.put("code", "9999");
			}

			//写文件方法用下面
			//response.writeBody(new File("E:\\a\\b\\aa1.pdf"), null);
		}
		return result;
	}

	/**
	 * 获取时间戳
	 *
	 * @return String
	 */
	public static String getDataExchangeId() {
		// enterpriseCode+8 位日期
		// (YYYYMMDD)+9 位序列号
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
		StringBuilder sb = new StringBuilder();
		Random rand = new Random();
		for (int i = 0; i < 9; i++) {
			sb.append(rand.nextInt(10));
		}
		String data = sb.toString();
		return CoreConstants.enterpriseCode + simpleDateFormat.format(new Date()) + data;
	}

	/**
	 * 加密方法
	 */
	public static String makeAppSec(String data, String dataExchangeId, String interfaceCode, String aceId, String aceKey) {
		String srcStr =
				"POST/rest/invoice/invoiceDownFile?authorize={\"appSecId\":\"" + aceId + "\"}&globalInfo={\"appId\":\"" + CoreConstants.appId
						+ "\",\"version\":\"" + CoreConstants.version + "\",\"interfaceCode\":\"" + interfaceCode + "\",\"enterpriseCode\":\""
						+ CoreConstants.enterpriseCode + "\",\"dataExchangeId\":\"" + dataExchangeId + "\"}&" + "data=" + data + "";
		log.info("待加密的请求：" + srcStr);
		SecretKeySpec keySpec = null;
		keySpec = new SecretKeySpec(aceKey.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
		Mac mac = null;
		try {
			mac = Mac.getInstance("HmacSHA1");
		} catch (NoSuchAlgorithmException e) {
			log.info("业务处理异常：{}", e);
		}
		try {
			mac.init(keySpec);
		} catch (InvalidKeyException e) {
			log.info("业务处理异常：{}", e);
		}
		byte[] singBytes = new byte[0];
		singBytes = mac.doFinal(srcStr.getBytes(StandardCharsets.UTF_8));
		String appSec = Base64.encode(singBytes);
		log.info("interfaceCode接口生成的加密串=appSec--");
		return appSec;
	}

}
