package com.hzya.frame.plugin.cinvoice.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hzya.frame.plugin.cinvoice.assembler.*;
import com.hzya.frame.plugin.cinvoice.entity.CInvoiceImportHEntity;
import com.hzya.frame.plugin.cinvoice.lexmis.entity.*;
import com.hzya.frame.plugin.cinvoice.lexmis.service.*;
import com.hzya.frame.plugin.cinvoice.service.ICInvoiceImportHService;
import com.hzya.frame.plugin.cinvoice.service.ICInvoiceImportPluginService;
import com.hzya.frame.seeyon.util.YzfSignUtil;
import com.hzya.frame.sysnew.integtationTaskLivingDetails.entity.IntegrationTaskLivingDetailsEntity;
import com.hzya.frame.sysnew.integtationTaskLivingDetails.service.IIntegrationTaskLivingDetailsService;
import com.hzya.frame.web.exception.BaseSystemException;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description 有度税务发票批量导入
 * @Author xiangerlin
 * @Date 2025/4/21 17:30
 **/
@Service()
public class CInvoiceImportPluginServiceImpl implements ICInvoiceImportPluginService {
    Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private ILexmisPublicinfoService lexmisPublicinfoService;
    @Autowired
    private ICInvoiceImportHService cInvoiceImportHService;
    @Autowired
    private ILexmiscivInvoicemainService lexmiscivInvoicemainService;
    @Autowired
    private ILexmiscivInvoicedetailService lexmiscivInvoicedetailService;
    @Autowired
    private ILexmiscivTrainticketService lexmiscivTrainticketService;
    @Autowired
    private ILexmiscivPlaneticketService lexmiscivPlaneticketService;
    @Autowired
    ILexmiscivPlaneticketsService lexmiscivPlaneticketsService;
    @Autowired
    private ILexmiscivBusinvoiceService lexmiscivBusinvoiceService;
    @Resource
    private IIntegrationTaskLivingDetailsService taskLivingDetailsService;
    @Value("${zt.url:}")
    private String url;

    /**
     * 发票导入
     *
     * @param requestJson
     * @return
     * @throws Exception
     */
    @Override
    public String importInvoice(JSONObject requestJson) throws Exception {


        //1、 查OA主表
        String dataSourceCode = requestJson.getString("sourceCode");
        if (StrUtil.isEmpty(dataSourceCode)) {
            dataSourceCode = requestJson.getString("apiDataSourceCode");
        }
        String id = requestJson.getString("id");//主表id 测试的时候用
        CInvoiceImportHEntity importHEntity = new CInvoiceImportHEntity();
        importHEntity.setDataSourceCode(dataSourceCode);
        importHEntity.setId(id);
        List<CInvoiceImportHEntity> cInvoiceImportHList = cInvoiceImportHService.queryInvoiceList(importHEntity);
        if (CollectionUtils.isNotEmpty(cInvoiceImportHList)) {
            ParamAssembler assembler = null;
            CInvoiceImportHEntity cInvoiceH = cInvoiceImportHList.get(0);
            cInvoiceH.setDataSourceCode(dataSourceCode);
            //2、 查OA明细表
            //3、 查迈瑞思发票表
            //迈锐思发票公共信息表
            logger.info("开始查迈锐思发票公共表信息:{},{}",cInvoiceH.getId(),cInvoiceH.getBill_code());
            LexmisPublicinfoEntity lexmisPublicinfoEntity = new LexmisPublicinfoEntity(cInvoiceH.getId(), dataSourceCode);
            //lexmisPublicinfoEntity.setPI_ID("6952494198841691018");
            List<LexmisPublicinfoEntity> lexmisPublicinfoEntityList = lexmisPublicinfoService.query(lexmisPublicinfoEntity);
            if (CollectionUtils.isNotEmpty(lexmisPublicinfoEntityList)) {
                cInvoiceH.setPush_status("1");
                cInvoiceImportHService.updateStatus(cInvoiceH);
                //税务接口每次最多传50张发票
                int size = lexmisPublicinfoEntityList.size();
                int batchSize = 50;
                for (int i = 0; i < size; i += batchSize) {
                    try {
                        int no = 1;//序号
                        //4、 根据发票类型，组装不同参数
                        JSONObject head = new JSONObject();
                        JSONArray inputInfos = new JSONArray();
                        head.put("inputInfos", inputInfos);//发票录入信息，单次最大50张
                        // 获取当前批次的子列表
                        List<LexmisPublicinfoEntity> batchList = lexmisPublicinfoEntityList.subList(i, Math.min(i + batchSize, size));
                        //使用stream方式 publicinfoList 按 PI_TABLENAME分组
                        Map<String, List<LexmisPublicinfoEntity>> groupedByPiTablename = batchList.stream()
                                .collect(Collectors.groupingBy(LexmisPublicinfoEntity::getPI_TABLENAME));
                        for (Map.Entry<String, List<LexmisPublicinfoEntity>> entry : groupedByPiTablename.entrySet()) {
                            String key = entry.getKey();//对应发票类型的表名
                            List<LexmisPublicinfoEntity> publicinfoList = entry.getValue();
                            for (LexmisPublicinfoEntity info : publicinfoList) {

                                JSONObject inputInfo = new JSONObject();
                                inputInfos.add(inputInfo);
                                inputInfo.put("no", no);//编号
                                inputInfo.put("systemName", "4");//来源系统 默认写4 代表OA
                                inputInfo.put("businessNo", cInvoiceH.getBill_code());//业务单据号
                                inputInfo.put("bookkeepingStatus", "1");//记账状态，默认传1
                                inputInfo.put("customFlag", "2");//业务流转状态，默认传2
                                JSONObject invoiceInfo = new JSONObject();//票面信息
                                inputInfo.put("invoiceInfo", invoiceInfo);
                                JSONObject baseInfo = new JSONObject();//发票基本信息
                                JSONObject contentInfo = new JSONObject();//发票内容
                                JSONArray taxturnsInfos = new JSONArray();//进项转出信息
                                invoiceInfo.put("taxturnsInfos", taxturnsInfos);

                                switch (key) {
                                    case "LEXMISCIV_INVOICEMAIN"://增值税发票
                                        zzsInvoice(dataSourceCode, info, invoiceInfo, baseInfo);
                                        break;
                                    case "LEXMISCIV_TRAINTICKET"://火车票
                                        trainInvoice(dataSourceCode, inputInfos, info, inputInfo, invoiceInfo, baseInfo);
                                        break;
                                    case "LEXMISCIV_PLANETICKET"://飞机行程单
                                        planeInvoice(dataSourceCode, info, invoiceInfo, baseInfo);
                                        break;
                                    case "LEXMISCIV_BUSINVOICE"://客运汽车票
                                        busInvoice(dataSourceCode, info, invoiceInfo, baseInfo);
                                        break;
                                    default:
                                        logger.info("没有匹配到类型");
                                        break;
                                }
                                no++;
                            }
                            head.put("taxNo", publicinfoList.get(0).getPI_TAXNO());//当前企业税号
                        }
                        logger.info("调用有度发票批量导入接口请求参数:{}", head.toString());
                        //调用税务接口
                        Map<String, String> headerMap = MapBuilder.<String, String>create(true)
                                .put("apiCode", "8000600005")//有度发票导入接口
                                .put("publicKey", "ZJYA7f8FzV219otH8zhkReiyyWpXswpbY/+StvC2em0hf59Ce7eDIk+3zDUT+v578prj")//发起方应用
                                .put("secretKey", "xJ9J1Ev2F0faiJ/nQnCNklskAgtQp3QSm+ihO21uY/H0UADj0tSDPxmIhFfC4v6Fj3JzOP8MtA1LSGvL+2BWG8c/o7DKi92S4mr3zcGearA=")//发起方应用
                                .put("appId", "800060")
                                .build();
                        String body = HttpRequest.post(url).addHeaders(headerMap).body(head.toString()).timeout(60000).execute().body();
                        //String body = null;
                        logger.info("调用有度发票批量导入接口响应参数:{}", body);
                        //保存操作日志
                        if (StrUtil.isNotEmpty(body)) {
                            JSONObject jsonObject = JSONObject.parseObject(body);
                            Boolean flag = jsonObject.getBoolean("flag");
                            JSONObject resObj = jsonObject.getJSONObject("attribute");
                            if (null != resObj && "0".equals(resObj.getString("code"))) {
                                String result = resObj.getString("result");
                                if (StrUtil.isNotEmpty(result)) {
                                    cInvoiceH.setDataSourceCode(dataSourceCode);
                                    cInvoiceH.setYd_result(result);
                                    cInvoiceImportHService.updateResultId(cInvoiceH);
                                }
                            }
                            //保存日志
                            IntegrationTaskLivingDetailsEntity taskLivingDetail = new IntegrationTaskLivingDetailsEntity();
                            taskLivingDetail.setCreate_time(new Date());
                            taskLivingDetail.setModify_time(new Date());
                            taskLivingDetail.setRootAppPk(cInvoiceH.getId());
                            taskLivingDetail.setRootAppBill(cInvoiceH.getBill_code());
                            taskLivingDetail.setPluginId("CInvoiceImportPluginInitializer");
                            taskLivingDetail.setRootAppNewData(head.toString());
                            taskLivingDetail.setNewTransmitInfo(body);
                            taskLivingDetail.setNewPushDate(new Date());
                            this.saveLog(id, flag, taskLivingDetail);
                        }
                    } catch (Exception e) {
                        logger.error("发票批量导入有度系统循环中出错:{}", e.getMessage());
                    }
                }
            }else {
                cInvoiceH.setPush_status("未查询到有效数据不推送");
                cInvoiceImportHService.updateStatus(cInvoiceH);
            }
        }


        return null;
    }


    /**
     * 保存日志
     *
     * @param integration_task_living_details_id
     * @param flag
     * @param taskLivingDetail
     */
    public void saveLog(String integration_task_living_details_id, Boolean flag, IntegrationTaskLivingDetailsEntity taskLivingDetail) {
        try {
            //判断，成功调用这个方法
            if (StrUtil.isEmpty(integration_task_living_details_id)) {
                if (flag) {
                    taskLivingDetailsService.saveLogToSuccess(taskLivingDetail);
                } else {
                    //失败 调用这个方法
                    taskLivingDetailsService.saveLogToFail(taskLivingDetail);
                }
            } else {
                taskLivingDetail.setId(integration_task_living_details_id);
                if (flag) {
                    //如果是重试 成功调这个方法
                    taskLivingDetailsService.saveLogFailToSuccess(taskLivingDetail);
                } else {
                    //如果是重试 失败调这个方法
                    taskLivingDetailsService.updateLogFailToSuccess(taskLivingDetail);
                }
            }
        } catch (Exception e) {
            logger.error("保存日志出错:{}", e);
        }
    }

    /**
     * 机票
     *
     * @param dataSourceCode
     * @param info
     * @param invoiceInfo
     * @param baseInfo
     */
    private void planeInvoice(String dataSourceCode, LexmisPublicinfoEntity info, JSONObject invoiceInfo, JSONObject baseInfo) {
        ParamAssemblerContext context;//策略上下文类
        JSONObject contentInfo;
        ParamAssembler assembler;
        LexmiscivPlaneticketEntity planeticketH = lexmiscivPlaneticketService.queryOne(new LexmiscivPlaneticketEntity(info.getPI_DATAKEY(), dataSourceCode));
        if (null != planeticketH) {
            String fplx = "a4";
            LexmiscivPlaneticketsEntity planeticketB = new LexmiscivPlaneticketsEntity(planeticketH.getPT_ID(), dataSourceCode);
            //飞机行程单子表
            List<LexmiscivPlaneticketsEntity> planeticketBList = lexmiscivPlaneticketsService.query(planeticketB);
            JSONObject planeObj = new JSONObject();
            planeObj.put("planeticketH", JSONObject.toJSONString(planeticketH));
            planeObj.put("planeticketBList", JSONObject.toJSONString(planeticketBList));
            //1表示电子行程单  先不区分试试，策略类内部判断来实现区分
            if ("1".equals(planeticketH.getPT_ELECTRONICMARK())) {
                //assembler = new ElecFlightInvoiceAssembler(planeObj);
                fplx = "400";
            }
//                                        else {
//                                            assembler = new FlightInvoiceAssembler(planeObj);
//                                        }
            assembler = new ElecFlightInvoiceAssembler(planeObj);
            context = new ParamAssemblerContext(assembler);
            contentInfo = context.assemble();
            baseInfo.put("fphm", planeticketH.getPT_FPHM());//发票号码
            baseInfo.put("fpdm", "");//发票代码
            baseInfo.put("fplx", fplx);//发票类型
            baseInfo.put("kprq", planeticketH.getPT_MAKEDATE());//开票日期
            baseInfo.put("bhszje", planeticketH.getPT_NOTAXAMOUNT());//不含税总金额
            baseInfo.put("jym", planeticketH.getPT_VALIDCODE());//校验码
            baseInfo.put("bxje", planeticketH.getPT_NOTAXAMOUNT());//不含税实际报销金额
            baseInfo.put("jsse", "");//有效计算税额
            baseInfo.put("jsdkzq", "");//计算抵扣账期
            baseInfo.put("signPerson", "");//签收人
            baseInfo.put("signStatus", "1");//签收状态，默认传1
            invoiceInfo.put("baseInfo", baseInfo);
            invoiceInfo.put("contentInfo", contentInfo);
        }
    }

    /**
     * 火车票发票
     *
     * @param dataSourceCode
     * @param inputInfos
     * @param info
     * @param inputInfo
     * @param invoiceInfo
     * @param baseInfo
     */
    private void trainInvoice(String dataSourceCode, JSONArray inputInfos, LexmisPublicinfoEntity info, JSONObject inputInfo, JSONObject invoiceInfo, JSONObject baseInfo) {
        JSONObject contentInfo;
        ParamAssembler assembler;
        ParamAssemblerContext context;//策略上下文类
        LexmiscivTrainticketEntity trainticketEntity = new LexmiscivTrainticketEntity(info.getPI_DATAKEY(), dataSourceCode);
        trainticketEntity.setTT_BUSINESSTYPE(1);//1售票 2退票 3售票换开 4退票换开，3和4没遇到过，先查1
        LexmiscivTrainticketEntity trainticket = lexmiscivTrainticketService.queryOne(trainticketEntity);
        if (null != trainticket) {
            JSONObject trainObj = new JSONObject();
            trainObj.put("trainInvoice", JSONObject.toJSONString(trainticket));
            trainObj.put("publicInvoice", JSONObject.toJSONString(info));
            String fplx = "a2";
            //1是电子票
            if ("1".equals(trainticket.getTT_ELECTRONIC())) {
                assembler = new ElecTrainInvoiceAssembler(trainObj);
                fplx = "200";
            } else {
                assembler = new TrainInvoiceAssembler(trainObj);
            }
            context = new ParamAssemblerContext(assembler);
            contentInfo = context.assemble();
            baseInfo.put("fphm", trainticket.getTT_CODE());//发票号码
            baseInfo.put("fpdm", "");//发票代码 火车票不用传
            baseInfo.put("fplx", fplx);//发票类型
            baseInfo.put("kprq", DateUtil.format(trainticket.getTT_DATE(), "yyyy-MM-dd"));//开票日期
            baseInfo.put("bhszje", trainticket.getTT_NOTAXAMOUNT());//不含税总金额
            baseInfo.put("jym", "");//校验码
            baseInfo.put("bxje", trainticket.getTT_NOTAXAMOUNT());//不含税实际报销金额
            baseInfo.put("jsse", "");//有效计算税额
            baseInfo.put("jsdkzq", "");//计算抵扣账期
            baseInfo.put("signPerson", "");//签收人
            baseInfo.put("signStatus", "1");//签收状态，默认传1
            invoiceInfo.put("baseInfo", baseInfo);
            invoiceInfo.put("contentInfo", contentInfo);
        } else {
            inputInfos.remove(inputInfo);
            logger.info("根据pi_datakey没有查到火车票发票信息:{},发票号:{}", info.getPI_DATAKEY());
        }
    }

    /**
     * 增值税发票
     *
     * @param dataSourceCode 数据源编码
     * @param info           发票公共表
     * @param invoiceInfo    发票信息对象
     * @param baseInfo       发票基本数据对象
     */
    private void zzsInvoice(String dataSourceCode, LexmisPublicinfoEntity info, JSONObject invoiceInfo, JSONObject baseInfo) {
        ParamAssemblerContext context;//策略上下文类
        JSONObject contentInfo;
        ParamAssembler assembler;
        LexmiscivInvoicemainEntity zzsInvoiceH = lexmiscivInvoicemainService.queryOne(new LexmiscivInvoicemainEntity(info.getPI_DATAKEY(), dataSourceCode));
        //增值税发票表体
        List<LexmiscivInvoicedetailEntity> zzsInvoiceBList = lexmiscivInvoicedetailService.query(new LexmiscivInvoicedetailEntity(zzsInvoiceH.getIM_ID(), dataSourceCode));
        JSONObject zzs = new JSONObject();
        zzs.put("zzsInvoiceH", JSONObject.toJSONString(zzsInvoiceH));
        zzs.put("zzsInvoiceBList", JSONObject.toJSONString(zzsInvoiceBList));
        assembler = new ZzsInvoiceAssembler(zzs);
        context = new ParamAssemblerContext(assembler);
        contentInfo = context.assemble();
        baseInfo.put("fphm", zzsInvoiceH.getIM_FPHM());//发票号码
        baseInfo.put("fpdm", zzsInvoiceH.getIM_FPDM());//发票代码
        baseInfo.put("fplx", convertZzsFplx(zzsInvoiceH.getIM_TYPE()));//发票类型
        baseInfo.put("kprq", DateUtil.format(zzsInvoiceH.getIM_DATE(), "yyyy-MM-dd"));//开票日期
        baseInfo.put("bhszje", zzsInvoiceH.getIM_NOTAXAMOUNT());//不含税总金额
        baseInfo.put("jym", zzsInvoiceH.getIM_CHECKCODE());//校验码
        baseInfo.put("bxje", zzsInvoiceH.getIM_NOTAXAMOUNT());//不含税实际报销金额
        baseInfo.put("jsse", "");//有效计算税额
        baseInfo.put("jsdkzq", "");//计算抵扣账期
        baseInfo.put("signPerson", "");//签收人
        baseInfo.put("signStatus", "1");//签收状态，默认传1
        invoiceInfo.put("baseInfo", baseInfo);
        invoiceInfo.put("contentInfo", contentInfo);
    }

    /**
     * 客运汽车
     *
     * @param dataSourceCode 数据源编码
     * @param info           发票公共表嘻嘻
     * @param invoiceInfo    发票参数对象
     * @param baseInfo       发票base参数对象
     */
    private void busInvoice(String dataSourceCode, LexmisPublicinfoEntity info, JSONObject invoiceInfo, JSONObject baseInfo) {
        ParamAssemblerContext context;//策略上下文类
        JSONObject contentInfo;
        ParamAssembler assembler;
        LexmiscivBusinvoiceEntity businvoiceEntity = lexmiscivBusinvoiceService.queryOne(new LexmiscivBusinvoiceEntity(info.getPI_DATAKEY(), dataSourceCode));
        if (null != businvoiceEntity) {
            JSONObject busObj = new JSONObject();
            busObj.put("busInvoice", JSONObject.toJSONString(businvoiceEntity));
            busObj.put("publicInfoice", JSONObject.toJSONString(info));
            assembler = new BusInvoiceAssembler(busObj);
            context = new ParamAssemblerContext(assembler);
            contentInfo = context.assemble();
            baseInfo.put("fphm", businvoiceEntity.getBI_FPHM());//发票号码
            baseInfo.put("fpdm", businvoiceEntity.getBI_FPDM());//发票代码
            baseInfo.put("fplx", "a3");//发票类型
            baseInfo.put("kprq", DateUtil.format(businvoiceEntity.getBI_DATE(), "yyyy-MM-dd"));//开票日期
            baseInfo.put("bhszje", businvoiceEntity.getBI_NOTAXAMOUNT());//不含税总金额
            baseInfo.put("jym", "");//校验码
            baseInfo.put("bxje", businvoiceEntity.getBI_NOTAXAMOUNT());//不含税金额
            baseInfo.put("jsse", "");//有效计算税额
            baseInfo.put("jsdkzq", "");//计算抵扣账期
            baseInfo.put("signPerson", "");//签收人
            baseInfo.put("signStatus", "1");//签收状态，默认传1
            invoiceInfo.put("baseInfo", baseInfo);
            invoiceInfo.put("contentInfo", contentInfo);
        }
    }

    /**
     * 迈锐思增值税类发票类型转换成有度发票类型
     *
     * @param fplx 迈锐思发票类型
     * @return
     */
    private String convertZzsFplx(String fplx) {
        if (StrUtil.isNotEmpty(fplx)) {
            String youduFplx = null;
            switch (fplx) {
                case "01"://增值税专用发票
                    youduFplx = "01";
                    break;
                case "04"://增值税普通发票
                    youduFplx = "04";
                    break;
                case "10"://增值税电子普票
                    youduFplx = "10";
                    break;
                case "20"://增值税电子专票
                    youduFplx = "08";
                    break;
                case "31"://电子发票(增值税专票)
                    youduFplx = "31";
                    break;
                case "32"://电子发票(增值税普票)
                    youduFplx = "32";
                    break;
                case "14"://电子发票(通行费)
                    youduFplx = "14";
                    break;
            }
            return youduFplx;
        }
        return null;
    }
}
