package com.yc.ship.module.trade.service.invoice.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.util.json.JsonUtils;
import com.yc.ship.module.infra.api.config.ConfigApi;
import com.yc.ship.module.trade.dal.dataobject.invoice.InvoiceDO;
import com.yc.ship.module.trade.enums.invoice.InvoiceStatusEnum;
import com.yc.ship.module.trade.enums.invoice.InvoiceTypeEnum;
import com.yc.ship.module.trade.service.invoice.InvoiceLogService;
import com.yc.ship.module.trade.service.invoice.InvoiceService;
import com.yc.ship.module.trade.service.invoice.InvoiceSxlyService;
import com.yc.ship.module.trade.utils.DESUtil;
import com.yc.ship.module.trade.utils.HexUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;

import static com.yc.ship.module.trade.enums.ErrorCodeConstants.INVOICING_FAIL;


@Service
@Slf4j
public class InvoiceSxlyServiceImpl implements InvoiceSxlyService {
    @Resource
    private ConfigApi configApi;
    @Resource
    private InvoiceLogService invoiceLogService;
    @Resource
    @Lazy
    private InvoiceService invoiceService;


    private final String SUCCESS = "0000";


    /**
     * 开蓝票
     */
    @Override
    public CommonResult<InvoiceDO> invoiceIssuance(InvoiceDO invoice) {
        String userName = configApi.getPlatformConfigValueByKey("newinvoice.username");
        String msg = "";
        try {
            JSONObject reqBody = this.bulidRequestParam(invoice);

            String reqUrl = "/sims-api/invoice/api/v6/GenerateQdInvoice";
            String resultStr = this.sendRequest(reqBody, reqUrl, userName);
            invoiceLogService.saveInvoiceLog(invoice.getId(), "Kp_Fpkj", reqUrl, "", reqBody.toString(), resultStr);
            JSONObject resultObj = JSONUtil.parseObj(resultStr);
            String code = resultObj.getStr("CODE");
            msg = resultObj.getStr("RETURNMESSAGE");
            invoice.setCStatus(code);
            invoice.setCMsg(msg);
            if (SUCCESS.equals(code)) {
                JSONObject dataObj = JSONUtil.parseObj(resultObj.getStr("DATA"));
                String kprq = dataObj.getStr("KPRQ");
                LocalDateTime localDateTime = this.getLocalDateTime(kprq);
                invoice.setCKprq(localDateTime);
                invoice.setCFphm(dataObj.getStr("FPHM"));
                invoice.setInvoiceStatus(InvoiceStatusEnum.INVOICE_SUCCESS.getValue());
                this.invoiceService.updateInvoice(invoice);
                return CommonResult.success(invoice);
            } else {
                log.error("开票失败：" + msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("发送开票请求失败:" + e.getMessage());
            return CommonResult.error(INVOICING_FAIL);
        }
        return CommonResult.error(INVOICING_FAIL.getCode(), msg);
    }

    private LocalDateTime getLocalDateTime(String kprq) {
        DateTime dateTime = DateUtil.parse(kprq);
        LocalDateTime localDateTime = LocalDateTimeUtil.of(dateTime);
        return localDateTime;
    }


    /**
     * 发票下载地址获取
     *
     * @param invoiceNo   发票号码
     * @param invoiceDate 开票日期 YYYYMMDDHHMMSS
     * @return
     */
    @Override
    public JSONObject queryInvoiceUrl(String invoiceNo, String invoiceDate) {
        String userName = configApi.getPlatformConfigValueByKey("newinvoice.username");
        try {
            JSONObject reqBody = new JSONObject();
            reqBody.set("FPHM", invoiceNo);
            reqBody.set("KPRQ", invoiceDate);

            String reqtUrl = "/openapi/qd/qpt/Yp_FpUrl";
            String resStr = this.sendRequest(reqBody, reqtUrl, userName);
            JSONObject resObj = JSONUtil.parseObj(resStr);
            if (SUCCESS.equals(resObj.getStr("CODE"))) {
                String data = this.decrypt(resObj.getStr("DATA"));
                JSONObject dataObj = JSONUtil.parseObj(data);
                return dataObj;
            } else {
                log.error("获取发票url失败: " + resObj.getStr("RETURNMESSAGE"));
            }
        } catch (Exception e) {
            log.error("获取发票url错误：" + e.getMessage());
        }
        return null;
    }

    /**
     * 组装参数
     *
     * @param invoice
     * @return
     */
    private JSONObject bulidRequestParam(InvoiceDO invoice) {
        String taxNum = configApi.getPlatformConfigValueByKey("newinvoice.group.tax");
        String senid = RandomUtil.randomNumbers(30 - taxNum.length());
        //流水号（生成规则：税号 +随机数 长度为30 唯一值）
        String serialNo = taxNum + senid;
        JSONObject body = new JSONObject();
        //发票行业代码
        body.put("FPHYDM", "0100");
        body.put("FPQQLSH", serialNo);
        JSONObject reqObj = new JSONObject();
        //系统自有单据号
        reqObj.put("DJH", invoice.getTransactionNo());
        //购买方名称
        reqObj.put("GMFMC", invoice.getBuyerName());
        //购货方税号
        reqObj.put("GMFSH", invoice.getBuyerTaxCode());
        //购买方开户行
        reqObj.put("GMFYH", invoice.getBuyerBank());
        //购方银行账号
        reqObj.put("GMFYHZH", invoice.getBuyerAccount());
        //购货方人员性质,0-个人 1-企业
        reqObj.put("GMFRYXZ", invoice.getTitleType());
        //购货方手机
        reqObj.put("GMFSJ", invoice.getBuyerTel());
        //购方邮箱,如填写，则由接口自动推送（有偿）
        reqObj.put("GMFYX", invoice.getBuyerEmail());
        //开票类型0-蓝票
        reqObj.put("KPLX", "0");
        //发票种类代码01-专用发票 02-普通发票
        if (invoice.getInvoiceType() == null) {
            reqObj.put("FPZLDM", "02");
        } else {
            reqObj.put("FPZLDM", InvoiceTypeEnum.valueOf(invoice.getInvoiceType()).getCode());
        }
        //开票员，以电子税局绑定人员为准
        reqObj.put("KPR", invoice.getBuyerClerk());
        //销货方开户行
        reqObj.put("XHFKHH", configApi.getPlatformConfigValueByKey("newinvoice.sales.bank"));
        //getPlatformConfigValueByKey
        reqObj.put("XHFYHZH", configApi.getPlatformConfigValueByKey("newinvoice.sales.bankaccount"));

        JSONArray detailArray = new JSONArray();
        JSONObject detailObj = null;
//        //合计金额
//        BigDecimal taxExcludedTotal = BigDecimal.ZERO;
//        //合计税额
//        BigDecimal seTotal = BigDecimal.ZERO;
//        BigDecimal taxIncludedTotal = BigDecimal.ZERO;
        int index = 1;

        detailObj = new JSONObject();
        detailObj.put("XH", index);
        //商品名称
        detailObj.put("SPMC", configApi.getPlatformConfigValueByKey("newinvoice.goods.name"));
        String GoodsCode = configApi.getPlatformConfigValueByKey("newinvoice.goods.code");
        String spbm = StrUtil.padAfter(GoodsCode, 19, "0");
        //商品编码
        detailObj.put("SPBM", spbm);
        //商品简码
        detailObj.put("SPJM", "*" + configApi.getPlatformConfigValueByKey("newinvoice.goods.simpleCode") + "*");
        //税率
        BigDecimal taxRate = new BigDecimal(configApi.getPlatformConfigValueByKey("newinvoice.taxRate"));
        detailObj.put("SLV", taxRate);
        //含税金额
        BigDecimal taxIncludedAmount = invoice.getPrice();
        //不含税金额
        BigDecimal taxExcludedAmount = taxIncludedAmount.divide(new BigDecimal(1).add(taxRate), 2, BigDecimal.ROUND_HALF_UP);
        //金额
        detailObj.put("JE", taxIncludedAmount);
        //税额
        BigDecimal se = taxIncludedAmount.divide(new BigDecimal(1).add(taxRate), 2, BigDecimal.ROUND_HALF_UP).multiply(taxRate).setScale(2, BigDecimal.ROUND_HALF_UP);

        detailObj.put("SE", se);
        //扣除额
        detailObj.put("KCE", "");
        //行性质。0-正常行 1-折扣行 2-被折扣行
        detailObj.put("HXZ", "0");
        //含税标志
        detailObj.put("HSBZ", "1");
        //零税率标识,0-非0税率 1-零税率
        detailObj.put("LSLBS", "0");

        detailArray.add(detailObj);
        //合计金额
        reqObj.put("HJJE", taxExcludedAmount);
        //合计税额
        reqObj.put("HJSE", se);
        //价税合计
        reqObj.put("JSHJ", taxIncludedAmount);
        reqObj.put("MXLIST", detailArray);
        body.put("REQUEST", reqObj);
        invoice.setCHjse(se);
        invoice.setCBhsje(taxExcludedAmount);
        return body;
    }

    /**
     * 公共请求方法
     *
     * @param reqBody
     * @param path
     * @param userName
     * @return
     * @throws Exception
     */
    private String sendRequest(JSONObject reqBody, String path, String userName) throws Exception {
        String url = configApi.getPlatformConfigValueByKey("newinvoice.group.url");
        String secretkey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
        String appId = configApi.getPlatformConfigValueByKey("newinvoice.group.secretId");
        // 加密数据

        String paramStr = JsonUtils.toJsonString(reqBody);
        // 加密数据
        byte[] encryptedData = DESUtil.encrypt(paramStr.getBytes(StandardCharsets.UTF_8), secretkey);
        String contentData = HexUtil.byteToHexString(encryptedData);

        JSONObject params = new JSONObject();
        params.set("APPID", appId);
        params.set("DATA", contentData);
        //电子税局登录账号
        params.set("USERNAME", userName);
        log.error("发票请求参数：{}", url + path + "--" + JsonUtils.toJsonString(params));
        String resultStr = HttpUtil.createPost(url + path).contentType("application/json")
                .body(JsonUtils.toJsonString(params))
                .timeout(15000)
                .execute().body();
        log.error("电子发票返回：{}", resultStr);
        JSONObject resObj = JSONUtil.parseObj(resultStr);

        String res = this.decrypt(resObj.getStr("DATA"));
        return res;
    }

    private String decrypt(String data) {
        String result = null;
        try {
            String secretkey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
            byte[] encryptedResponse = HexUtil.parseHexStr2Byte(data);
            byte[] decryptedData = DESUtil.decrypt(encryptedResponse, secretkey);
            result = new String(decryptedData).trim();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


}
