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

import cn.hutool.core.codec.Base64;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.dxhy.api.model.invoice.TDxRecordInvoice;
import com.dxhy.common.constant.ConfigureConstant;
import com.dxhy.common.constant.CoreConstants;
import com.dxhy.common.constant.DbConstant;
import com.dxhy.common.datasource.config.DynamicContextHolder;
import com.dxhy.common.enums.FplxEnum;
import com.dxhy.common.utils.CommonUtil;
import com.dxhy.core.job.dao.CheckOneDao;
import com.dxhy.core.job.entity.TAcOrg;
import com.dxhy.core.job.pojo.*;
import com.dxhy.core.job.service.CheckOneService;
import com.dxhy.jxpt.baseService.poolPush.PoolLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;

@Service("checkOneService")
@Slf4j
public class CheckOneServiceImpl implements CheckOneService {

    private String secretId;
    private String secretKey;

    @Resource
    private PoolLogService poolLogService;

    @Resource
    private CheckOneDao checkOneDao;

    //获取所需要查验相关税号
    @Override
    public List<TAcOrg> getTaxNo() {
        List<TAcOrg> taxNoList = checkOneDao.getTaxNo();
        return taxNoList;
    }

    @Override
    public List<TDxRecordInvoice> getRecordList(String taxNo, int rows) {
        return checkOneDao.getRecordList(taxNo, rows);
    }

    @Override
    public void updateStatus(String uuid) {
        checkOneDao.updateStatus(null, uuid, "3");
    }

    @Override
    public void reqCheck(TDxRecordInvoice invoiceSave,TAcOrg taxOrg) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        //设置调用接口请求需要的参数
        RequestData requestData = new RequestData();
        requestData.setBuyerTaxNo(invoiceSave.getGfTaxNo());
        requestData.setInvoiceAmount(invoiceSave.getInvoiceAmount() != null ?
                invoiceSave.getInvoiceAmount().setScale(2, BigDecimal.ROUND_HALF_UP).toString() : "");
        if (FplxEnum.ESC.getFplxDm().equals(invoiceSave.getInvoiceType())) {
            requestData.setInvoiceAmount(invoiceSave.getTotalAmount() != null ?
                    invoiceSave.getTotalAmount().setScale(2, BigDecimal.ROUND_HALF_UP).toString() : "");
        }
        requestData.setCheckCode(invoiceSave.getCheckCode());
        requestData.setInvoiceCode(invoiceSave.getInvoiceCode());
        requestData.setInvoiceNo(invoiceSave.getInvoiceNo());
        requestData.setInvoiceDate(formatter.format(invoiceSave.getInvoiceDate()));
        requestData.setInvoiceType(invoiceSave.getInvoiceType());
        ResponseInvoice r = this.sendRequest(requestData,taxOrg);
        DynamicContextHolder.push(taxOrg.getDbName() + DbConstant.BUSINESS_READ);
        if (r != null) {
            if ("0001".equals(r.getResultCode())) {
                try {
                    String invoiceStatus = "";
                    if (StringUtils.isBlank(r.getIsCancelled())) {
                        invoiceStatus = "0";
                    } else {
                        //发票状态
                        if ("N".equals(r.getIsCancelled())) {//正常
                            invoiceStatus = "0";
                        } else if ("0".equals(r.getIsCancelled())) {//正常
                            invoiceStatus = "0";
                        } else if ("3".equals(r.getIsCancelled())) {//红冲
                            invoiceStatus = "3";
                        } else {
                            invoiceStatus = "2";
                        }
                    }
                    checkOneDao.updateStatus(invoiceStatus, r.getInvoiceCode() + r.getInvoiceNo(), "1");

                    //推送新票池记录表
                    poolLogService.pushChangeToPool(ConfigureConstant.POOL_SJLX_JXFP_1, CommonUtil.getUuid(r.getInvoiceCode(),r.getInvoiceNo()), ConfigureConstant.POOL_BGLX_ZTBG_2);
                } catch (Exception e) {
                   log.info("业务处理异常：{}", e);
                }
            } else {
                checkOneDao.updateStatus(null, r.getInvoiceCode() + r.getInvoiceNo(), "2");

            }
        } else {
            checkOneDao.updateStatus(null, r.getInvoiceCode() + r.getInvoiceNo(), "2");
        }
    }



    public ResponseInvoice sendRequest(RequestData requestData,TAcOrg taxOrg) {

        //根据标识判断是否需要获取数据库权限数据
        if (CoreConstants.enterprisePermissionFlag) {
            secretId = taxOrg.getAceId();
            secretKey = taxOrg.getAceKey();
        }
        // 定义返回值
        ResponseInvoice responseInvoice = null;

        // 请求通用头
        final GlobalInfo globalInfo = new GlobalInfo();
        // 请求通用
        final Authorize authorize = new Authorize();

        final BaseQueJson bqj = new BaseQueJson();

        try {
            // 封装参数
            globalInfo.setAppId(CoreConstants.appId);
            globalInfo.setVersion(CoreConstants.version);
            String dataExchangeId = getDataExchangeId();
            globalInfo.setDataExchangeId(dataExchangeId);
            globalInfo.setInterfaceCode(CoreConstants.invoiceCheckOne);
            globalInfo.setEnterpriseCode(CoreConstants.enterpriseCode);

            authorize.setAppSecId(secretId);

            String dataStr = JSONObject.toJSONString(requestData);

            log.info("更新发票状态查验接口参数,data：{}", dataStr);
            String base64Data = Base64.encode(dataStr);

            String appSec = makeAppSec(base64Data, dataExchangeId, CoreConstants.invoiceCheckOne, secretId, secretKey);
            authorize.setAppSec(appSec);
            bqj.setAuthorize(authorize);
            bqj.setGlobalInfo(globalInfo);

            bqj.setData(base64Data);
            String collectDataStr = JSONObject.toJSONString(bqj);

            log.info("url:{}",CoreConstants. collectUrl);
            log.info("请求参数：{}", collectDataStr);
            log.info("------------------更新发票状态查验接口发送请求-----------------");
            final String responseJson = HttpUtil.post(CoreConstants.collectUrl, collectDataStr, 600000);

            log.info("返回报文:{}", responseJson);

            final BaseResJson baseResJson = JSONObject.parseObject(responseJson, BaseResJson.class);

            if ("0000".equals(baseResJson.getReturnStateInfo().getReturnCode())) {
                String dataJson = Base64.decodeStr(baseResJson.getData());
                log.info("data体：{}", dataJson);
                responseInvoice = JSONObject.parseObject(dataJson, ResponseInvoice.class);
            }

        } catch (Exception e) {
           log.info("业务处理异常：{}", e);
            log.info("查验异常，发票信息重置-InvoiceCode{}，InvoiceNo{}",requestData.getInvoiceCode(),requestData.getInvoiceNo());
            DynamicContextHolder.push(taxOrg.getDbName() + DbConstant.BUSINESS_READ);
            checkOneDao.updateStatus(null, requestData.getInvoiceCode() + requestData.getInvoiceNo(), "0");
            log.error("手动验证失败:{}", e.getMessage());
        }
        return responseInvoice;
    }

    /**
     * 生成交换流水号
     *
     * @return
     */
    private 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 String makeAppSec(String data, String dataExchangeId, String interfaceCode, String secretId,
                             String secretKey) {
        String srcStr =
                "POST/rest/invoice/dii?authorize={\"appSecId\":\"" + secretId + "\"}&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(secretKey.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;
    }

    @Override
    public void updateFailStatus(TAcOrg tAcOrg) {
        DynamicContextHolder.push(tAcOrg.getDbName() + DbConstant.BUSINESS_READ);
        checkOneDao.updateFailStatus(tAcOrg.getTaxno());
    }

    @Override
    public List<TDxRecordInvoice> getRecordListThreeMonth(String taxNo, Integer rows) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
        Date date = new Date();
        String monthBegin = this.getLastMonth();
        String monthEnd = format.format(date);
        return checkOneDao.getRecordListThreeMonth(taxNo, rows, monthBegin, monthEnd);
    }

    public String getLastMonth() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date); // 设置为当前时间
        calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 3);
        date = calendar.getTime();
        String accDate = format.format(date);
        return accDate;
    }
}
