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.dal.dataobject.invoice.InvoiceDetailDO;
import com.yc.ship.module.trade.dal.mysql.invoice.InvoiceMapper;
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.InvoiceDetailService;
import com.yc.ship.module.trade.service.invoice.InvoiceHangxinService;
import com.yc.ship.module.trade.service.invoice.InvoiceLogService;
import com.yc.ship.module.trade.service.invoice.InvoiceService;
import com.yc.ship.module.trade.utils.DESUtil;
import com.yc.ship.module.trade.utils.HexUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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 java.util.List;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.*;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.INVOICING_FAIL;


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

    @Resource
    @Lazy
    private InvoiceMapper invoiceMapper;

    @Resource
    private InvoiceDetailService invoiceDetailService;

    //TODO
//    @Resource
//    private TradeOrderRepositoryService tradeOrderRepositoryService;

//    private static String taxNum = "";
//    private static String url = "";
//    private static String appId = "";
//    private static String secretkey = "";
//    private static String userName = "";


    private final String SUCCESS = "0000";

//    @PostConstruct
//    public void init() {
//        try {
//            taxNum = configApi.getConfigValueByKey("invoice.tax");
//            url = configApi.getConfigValueByKey("invoice.url");
//            appId = configApi.getConfigValueByKey("invoice.appId");
//            secretkey = configApi.getConfigValueByKey("invoice.secretkey");
//            userName = configApi.getConfigValueByKey("invoice.username");
//            password = configApi.getConfigValueByKey("invoice.password");
//        } catch (Exception e) {
//            log.error("发票参数初始化失败！");
//        }
//    }


    @Override
    public Boolean login(String username, String password) {
        boolean flag = false;

        JSONObject loginOneRes = this.loginStepOne(username, password, null);
        if (!SUCCESS.equals(loginOneRes.getStr("CODE"))) {
            String msg = loginOneRes.getStr("RETURNMESSAGE");
            log.error("发票登录失败：" + msg);
            throw exception0(15_004_98, "发票登录失败: " + msg);
        }
        String loginData = loginOneRes.getStr("DATA");
        String decryptData = this.decrypt(loginData);
        JSONObject loginResData = JSONUtil.parseObj(decryptData);
        String status = loginResData.getStr("STATUS");
        // 设置 SMSCODE
        String smscode = configApi.getPlatformConfigValueByKey("invoice.smscode");
//        if ("0".equals(status)) {
//            smsCode = RandomUtil.randomNumbers(6);
//        } else {
//            smsCode = smscode; // 替换为实际的验证码
//        }
        // 登录第二步
        JSONObject loginTwoRes = this.loginStepTwo(username, smscode);
        if (SUCCESS.equals(loginTwoRes.getStr("CODE"))) {
            flag = true;
        }
        return flag;
    }

    @Override
    public JSONObject loginStepOne(String username, String password, String userIdentity) {
        JSONObject res = null;
        try {
            JSONObject reqBody = new JSONObject();
            reqBody.set("PASSWORD", password);
            reqBody.set("USERNAME", username);
            reqBody.set("YHSF", userIdentity);
            String reqtUrl = "/openapi/qd/qpt/Dr_Login1";

            String resStr = this.sendRequest(reqBody, reqtUrl, username);
            log.error("发票登录第一步Dr_Login1：" + resStr);
            res = JSONUtil.parseObj(resStr);
        } catch (Exception e) {
            log.error("发票登录第一步失败：" + e.getMessage());
        }
        return res;
    }


    @Override
    public JSONObject loginStepTwo(String username, String smsCode) {
        JSONObject res = null;
        try {
            String reqtUrl = "/openapi/qd/qpt/Dr_Login2"; // 登录第二步的接口地址
            JSONObject reqBody = new JSONObject();
            reqBody.put("SMSCODE", smsCode);
            String resStr = this.sendRequest(reqBody, reqtUrl, username);
            log.error("发票登录第一步Dr_Login2：" + resStr);
            res = JSONUtil.parseObj(resStr);
        } catch (Exception e) {
            log.error("发票登录第二步失败：" + e.getMessage());
        }
        return res;
    }

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

            String reqUrl = "/openapi/qd/qpt/Kp_Fpkj";
            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"));
                try {
                    String kprq = dataObj.getStr("KPRQ");
                    LocalDateTime localDateTime = this.getLocalDateTime(kprq);
                    invoice.setCKprq(localDateTime);
                    invoice.setCFphm(dataObj.getStr("FPHM"));
                    invoice.setInvoiceStatus(InvoiceStatusEnum.INVOICE_SUCCESS.getValue());
                    invoiceMapper.updateById(invoice);
//                    invoiceService.updateInvoice(invoice);
                }catch (Exception e){
                    log.error("开票error：" + invoice.getId());
                    log.error("开票error：" + e.getStackTrace());
                }
                return CommonResult.success(invoice);
            } else {
                log.error("开票失败：" + msg);
                //调用任何接口前 需要登录成功状态，才能访问接口
                if (StringUtils.contains(msg, "登入超时")) {
                    String password = configApi.getPlatformConfigValueByKey("invoice.password");
                    Boolean flag = this.login(userName, password);
                    if (flag) {
                        resultStr = this.sendRequest(reqBody, reqUrl, userName);
                        JSONObject aginRes = JSONUtil.parseObj(resultStr);
                        msg = aginRes.getStr("RETURNMESSAGE");
                        if (SUCCESS.equals(aginRes.getStr("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());
                            invoiceMapper.updateById(invoice);
                            return CommonResult.success(invoice);
                        }
                    }
                }
                invoiceMapper.updateById(invoice);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("发送开票请求失败:" + e.getMessage());
            invoice.setCStatus("500");
            invoice.setCMsg("发送开票请求失败:" + e.getMessage());
            invoiceMapper.updateById(invoice);
            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(Long invoiceId ,String invoiceNo, String invoiceDate) {
        String userName = configApi.getPlatformConfigValueByKey("invoice.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 = resObj.getStr("DATA");
                JSONObject dataObj = JSONUtil.parseObj(data);
                return dataObj;
            } else {
                List<InvoiceDetailDO> invoiceDetails = invoiceDetailService.getInvoiceDetails(invoiceId);
                List<String> orderNoList = invoiceDetails.stream().map(InvoiceDetailDO::getOrderNo).collect(Collectors.toList());
                //TODO
//                tradeOrderRepositoryService.updateInvoiceStatusByOrderNo(orderNoList, InvoiceStatusEnum.INVOICE_FAILED.getValue());
                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("invoice.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("invoice.sales.bank"));
        //getPlatformConfigValueByKey
        reqObj.put("XHFYHZH", configApi.getPlatformConfigValueByKey("invoice.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("invoice.goods.name"));
        String GoodsCode = configApi.getPlatformConfigValueByKey("invoice.goods.code");
        String spbm = StrUtil.padAfter(GoodsCode, 19, "0");
        //商品编码
        detailObj.put("SPBM", spbm);
        //商品简码
        detailObj.put("SPJM", "*" + configApi.getPlatformConfigValueByKey("invoice.goods.simpleCode") + "*");
        //税率
        BigDecimal taxRate = new BigDecimal(configApi.getPlatformConfigValueByKey("invoice.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);
        BigDecimal se = taxIncludedAmount.subtract(taxExcludedAmount);

        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("invoice.url");
        String secretkey = configApi.getPlatformConfigValueByKey("invoice.secretkey");
        String appId = configApi.getPlatformConfigValueByKey("invoice.appId");
        // 加密数据

        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("invoice.secretkey");
            log.error("发票decrypt请求参数：{},{}", data,secretkey);
            byte[] encryptedResponse = HexUtil.parseHexStr2Byte(data);
            byte[] decryptedData = DESUtil.decrypt(encryptedResponse, secretkey);
            result = new String(decryptedData).trim();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    public static void main(String[] args) {
        String s = "0B878F06C03B058BF97CD365C3BB420E242F8DD1F5DBEC6DB73B4498CF560600FC30F867426BCCFFDC11CBB5504ED4E680288690DA8102BB44C475879826B2C014F481BCA4F6EEF646286A38531730F3A1C4BCA757992C1014894AF2F479FD61994FAB67167CF8433B65CA245A58A62FBE67A6D32FAC8726A6C868DB593471712D9160601F06F5D3EA1127AF30A26909508586E158BB07B3EB19DDD531B7B1EFCF33C7AB91A58AD495B241913A66AFEF824A5B6B97736FA8F710C58E60C0E731FF6D62D9B043D5D746D574B3AA55644BC0824F7B976E617080077ADC482FC9F679758D364A2399123044F1969981DBBE1E7C2E7149EF599BBE93C5A3C688C4FE2F3B61C0AC77C98F754E7E1426B1C5B439D5ECFBE000DA35F36237B13A3E17B4E422645AB1FB8C9C633B2BE894EC22ABFDAC16A10F133BC9D3905FE6BF64F4EC700A42F32C1D7193AD613303718A6D0D5C072F23A079554600D149D3144F0D09763A5AB4DDD2A6ECD4FB94F3C3BD56C2C88CF151755F1790DCAC89593C9312483C825A3A943B99CF97621650A9A61226BB93670F2E83BD43CA64CE13691BFEA3F246B0072D30615D2020B22C6B201AD5924CD88944620CC0E5289E56D564EC491EF7DE47B68C4CCC27E67F6A2AE1F0011CCD3F2EF3E5085F25A5773F5C50BF11E61882CE600728B1CCA356282F231EC5F112629598DD455B4CE19F1B4BAC33AC057E77D4D21D3206CB1F640C790AE931DDE27D448ED9CBD91035357DBCFDA23A8358997430D1FE3071FFD1CDAF676016ACA122FC99D61A07";
        String result = null;
        try {
            String secretkey = "8717EE05";
            byte[] encryptedResponse = HexUtil.parseHexStr2Byte(s);
            byte[] decryptedData = DESUtil.decrypt(encryptedResponse, secretkey);
            result = new String(decryptedData).trim();
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


}
