package com.zt.plat.module.erp.service.erp;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.module.erp.api.ErpExternalApi;
import com.zt.plat.module.erp.api.dto.ErpSubmitReqDTO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpContractPageReqVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpContractRespVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpContractSaveReqVO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpContractDO;
import com.zt.plat.module.erp.dal.mysql.erp.ErpContractMapper;
import com.zt.plat.module.erp.enums.OftenEnum;
import com.zt.plat.module.erp.utils.ErpConfig;
import com.zt.plat.module.erp.utils.MyRedisConfig;
import com.zt.plat.module.system.api.user.AdminUserApi;
import com.zt.plat.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.erp.enums.ErrorCodeConstants.ERP_CONTRACT_NOT_EXISTS;

/**
 * ERP合同映射 Service 实现类
 *
 * @author 后台管理
 */
@Service
@Validated
public class ErpContractServiceImpl implements ErpContractService {

    @Resource
    private ErpContractMapper erpContractMapper;

    @Resource
    private MyRedisConfig myRedisConfig;
    @Resource
    private ErpConfig erpConfig;

    @Resource
    public ErpExternalApi erpExternalApi;

    @Resource
    private AdminUserApi adminUserApi;
    @Override
    public ErpContractRespVO createErpContract(ErpContractSaveReqVO createReqVO) {
        // 插入
        ErpContractDO erpContract = BeanUtils.toBean(createReqVO, ErpContractDO.class);
        erpContractMapper.insert(erpContract);
        // 返回
        return BeanUtils.toBean(erpContract, ErpContractRespVO.class);
    }

    @Override
    public void updateErpContract(ErpContractSaveReqVO updateReqVO) {
        // 校验存在
        validateErpContractExists(updateReqVO.getId());
        // 更新
        ErpContractDO updateObj = BeanUtils.toBean(updateReqVO, ErpContractDO.class);
        erpContractMapper.updateById(updateObj);
    }

    @Override
    public void deleteErpContract(Long id) {
        // 校验存在
        validateErpContractExists(id);
        // 删除
        erpContractMapper.deleteById(id);
    }

    @Override
    public void deleteErpContractListByIds(List<Long> ids) {
        // 校验存在
        validateErpContractExists(ids);
        // 删除
        erpContractMapper.deleteByIds(ids);
    }

    private void validateErpContractExists(List<Long> ids) {
        List<ErpContractDO> list = erpContractMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(ERP_CONTRACT_NOT_EXISTS);
        }
    }

    private void validateErpContractExists(Long id) {
        if (erpContractMapper.selectById(id) == null) {
            throw exception(ERP_CONTRACT_NOT_EXISTS);
        }
    }

    @Override
    public ErpContractDO getErpContract(Long id) {
        return erpContractMapper.selectById(id);
    }

    @Override
    public ErpContractDO getErpContractByPaperNumber(String paperNumber) {
        return erpContractMapper.selectOne("CTRT_PPR_NUM", paperNumber);
    }

    @Override
    public PageResult<ErpContractDO> getErpContractPage(ErpContractPageReqVO pageReqVO) {
        OftenEnum.FuncnrEnum funcnrEnum = OftenEnum.FuncnrEnum.合同信息;
        String funcnr = funcnrEnum.getFuncnr();
        Map<String, Object> req = new HashMap<>();

        // 构建查询参数
        req.put("BUKRS", pageReqVO.getContractSignNumber());
        req.put("PARTNER", pageReqVO.getSupplierNumber());
        req.put("INEDR", pageReqVO.getContractCategory());
        req.put("ZHTBH", pageReqVO.getContractTypeNumber());
        req.put("ZHTMC", pageReqVO.getContractName());

        // 调用ERP接口获取数据
        Map<String, Object> dataFromERP = erpConfig.fetchDataFromERP(funcnr, req);
        JSONArray dataArray = (JSONArray) dataFromERP.get("E_RESP");
        if (dataArray == null || dataArray.isEmpty()) {
            // 返回空结果而不是抛出异常
            return new PageResult<>(new ArrayList<>(), 0L);
        }

        List<ErpContractDO> list = new ArrayList<>();
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataJson = dataArray.getJSONObject(i);
            if (dataJson != null) {
                ErpContractDO contractDO = new ErpContractDO();

                // 基本信息
                contractDO.setContractPaperNumber(dataJson.getString("ZHTBH").trim());
                contractDO.setContractName(dataJson.getString("ZHTMC"));
                contractDO.setContractTypeName(dataJson.getString("TYPENM"));
                contractDO.setSupplierName(dataJson.getString("ZBPNM"));

                // 日期处理
                String signDate = dataJson.getString("ZQDATE");
                String startDate = dataJson.getString("ZSDATE");
                String stopDate = dataJson.getString("ZEDATE");

                if (signDate != null && !signDate.equals("0000-00-00")) {
                    try {
                        contractDO.setSignDate(LocalDate.parse(signDate));
                    } catch (Exception e) {
                        // 忽略日期解析错误
                    }
                }

                if (startDate != null && !startDate.equals("0000-00-00")) {
                    try {
                        contractDO.setStartDate(LocalDate.parse(startDate));
                    } catch (Exception e) {
                        // 忽略日期解析错误
                    }
                }

                if (stopDate != null && !stopDate.equals("0000-00-00")) {
                    try {
                        contractDO.setStopDate(LocalDate.parse(stopDate));
                    } catch (Exception e) {
                        // 忽略日期解析错误
                    }
                }
                contractDO.setBasicAmount(dataJson.getBigDecimal("ZDMBTR"));
                contractDO.setRemark(dataJson.getString("ZREMARK"));
                list.add(contractDO);
            }
        }
        // 返回分页结果
        return new PageResult<>(list, (long) list.size());
    }

    @Override
    @Transactional
    @XxlJob("getErpContractTask")
    public void callErpRfcInterface() {
        OftenEnum.FuncnrEnum funcnrEnum = OftenEnum.FuncnrEnum.合同信息;
        String funcnr = funcnrEnum.getFuncnr();

        Map<String, Object> req = new HashMap<>();
        JSONArray dataArrayALL = new JSONArray();
        String commanyKey = "erpMap" + OftenEnum.FuncnrEnum.公司代码.getFuncnr();
        Map<String, Long> redisCache = myRedisConfig.getRedisCacheMap(commanyKey);
        if (CollUtil.isEmpty(redisCache)) {
            return;
        }
        String cstmKey = "erpMap" + OftenEnum.FuncnrEnum.客商信息.getFuncnr();
        Map<String, Long> redisCachecstmKey = myRedisConfig.getRedisCacheMap(cstmKey);
        if (CollUtil.isEmpty(redisCachecstmKey)) {
            return;
        }
        // 1. 调用ERP接口获取数据
        for (String INEDR : new String[]{"1", "2"}) {
            req.put("INEDR", INEDR);
            for (String number : redisCache.keySet()) {
                req.put("BUKRS", number);
                for (String partner : redisCachecstmKey.keySet()) {
                    req.put("PARTNER", partner);

                    // 1. 调用ERP接口获取数据
                    Map<String, Object> dataFromERP = erpConfig.fetchDataFromERP(funcnr, null);
                    JSONArray dataArray = (JSONArray) dataFromERP.get("E_RESP");
                    if (dataArray != null) {
                        dataArrayALL.addAll(dataArray);
                    }
                }
            }
        }
        if (CollUtil.isEmpty(dataArrayALL)) {
            throw exception(ERP_CONTRACT_NOT_EXISTS);
        }

        // 2. 处理公司数据，区分新增和更新
        ProcessingResult result = processData(dataArrayALL, funcnrEnum);

        // 3. 批量保存数据
        saveData(result);
    }

    @Override
    public Map<String, String> submitErp(ErpContractSaveReqVO erpContractVO) {

        // 转换为DO
        ErpContractDO erpContract = BeanUtils.toBean(erpContractVO, ErpContractDO.class);

        // 根据合同编号查询合同映射
        ErpContractDO erpContractDO = getErpContractByPaperNumber(erpContract.getContractPaperNumber());
        if (erpContractDO == null) {
            // 不存在映射表则新增
            erpContract.setDeleted(false);
            erpContractMapper.insert(erpContract);
        } else {
            // 存在映射表则更新
            erpContract.setId(erpContractDO.getId());
            erpContractMapper.updateById(erpContract);
        }
        AdminUserRespDTO work = getWorkId();
        // 构建ERP接口的参数
        ErpSubmitReqDTO erpSubmitReqDTO = new ErpSubmitReqDTO();
        erpSubmitReqDTO.setFuncnr("060");
        erpSubmitReqDTO.setBskey(erpContract.getContractPaperNumber());
        erpSubmitReqDTO.setUsrid(work.getWorkcode());
        erpSubmitReqDTO.setUsrnm(work.getUsername());

        Map<String, Object> head = new HashMap<>();
        // CZBS 操作标识 枚举值0：新增 1：修改
        head.put("CZBS", erpContract.getOperationId());
        // HTBH 合同编号
        head.put("HTBH", erpContract.getContractPaperNumber());
        // HTMC 合同名称
        head.put("HTMC", erpContract.getContractName());
        // HTLXBH 合同类型编号
        head.put("HTLXBH", erpContract.getContractTypeNumber());
        // HTLXMC 合同类型名称
        head.put("HTLXMC", erpContract.getContractTypeName());
        // HTLB 合同类别 枚举值：1：购销合同
        head.put("HTLB", erpContract.getContractCategory());
        // SFXNHT 是否虚拟合同 枚举值 0：否 1：是
        head.put("SFXNHT", erpContract.getIsVirtualContract());
        // WLDWBH 客户/供应商编号 如果合同类型是收入类的，传客户编号和客户名称；
        head.put("WLDWBH", erpContract.getSupplierNumber());
        // WLDWMC 客户/供应商名称 如果合同类型是支出类的，传供应商编号和供应商名称；
        head.put("WLDWMC", erpContract.getSupplierName());
        // ZLIFNR 代理方
        head.put("ZLIFNR", erpContract.getAgent());
        // HTSSZTBH 合同实施主体编号 SAP公司代码
        head.put("HTSSZTBH", erpContract.getContractImplementNumber());
        // HTQDZTBH 合同签订主体编号 SAP公司代码
        head.put("HTQDZTBH", erpContract.getContractSignNumber());
        // HTQDRQ 合同签订日期 格式：YYYY-MM-DD
        head.put("HTQDRQ", erpContract.getSignDate());
        // HTQSRQ 合同起始日期 格式：YYYY-MM-DD
        head.put("HTQSRQ", erpContract.getStartDate());
        // HTZZRQ 合同终止日期 格式：YYYY-MM-DD
        head.put("HTZZRQ", erpContract.getStopDate());
        // BZBH 币种编号 CNY、USD…
        head.put("BZBH", erpContract.getCurrency());
        // HTYBZJE 合同总金额（原币-含税）
        head.put("HTYBZJE", erpContract.getSourceAmount());
        // HTBWBZJE 合同总金额（本位币-含税）
        head.put("HTBWBZJE", erpContract.getBasicAmount());
        // BGHHTYBZJE 变更后合同总金额（原币-含税） 如果未做合同变更，金额等于合同总金额（原币-含税）
        head.put("BGHHTYBZJE", erpContract.getChangeSourceAmount());
        // BGHHTBWBZJE 变更后合同总金额（本位币-含税） 如果未做合同变更，金额等于合同总金额（本位币-含税）
        head.put("BGHHTBWBZJE", erpContract.getChangeBasicAmount());
        // HTZTBH 合同状态编号
        head.put("HTZTBH", erpContract.getStatusNumber());
        // HTZTMC 合同状态名称
        head.put("HTZTMC", erpContract.getStatusName());
        // SFYYFK 是否有预付款 枚举值 0：否 1：是
        head.put("SFYYFK", erpContract.getIsPrepayment());
        // YFKBL 预付款比例 如果是否有预付款为1，则必填
        head.put("YFKBL", erpContract.getPrepaymentRatio());
        // YFKJE 预付款金额
        head.put("YFKJE", erpContract.getPrepaymentAmount());
        // LYBZJBGQYB 履约保证金-变更前（原币）
        head.put("LYBZJBGQYB", erpContract.getSourceBeforeBond());
        // LYBZJBGQBWB 履约保证金-变更前（本位币）
        head.put("LYBZJBGQBWB", erpContract.getBasicBeforeBond());
        // LYBZJBGHYB 履约保证金-变更后（原币）
        head.put("LYBZJBGHYB", erpContract.getSourceAfterBond());
        // LYBZJBGHBWB 履约保证金-变更后（本位币）
        head.put("LYBZJBGHBWB", erpContract.getBasicAfterBond());
        // SFHZBJ 是否含质保金 枚举值 0：否 1：是
        head.put("SFHZBJ", erpContract.getIsQualityassuranceAmount());
        // ZBJBL 质保金比例 如果是否含质保金为1，则必填
        head.put("ZBJBL", erpContract.getQualityassuranceRatio());
        // BZJJE 质保金金额
        head.put("BZJJE", erpContract.getQualityassuranceAmount());
        // SFNBQY 是否内部企业 枚举值 0：否 1：是
        head.put("SFNBQY", erpContract.getIsInternal());
        // SZXZ 收支性质 枚举值 1：收入 2：支出
        head.put("SZXZ", erpContract.getNature());
        // BZXX 备注信息
        head.put("BZXX", erpContract.getRemark());
        // SFKJHT 是否框架合同 0：否；1：是；当等于1时：合同总金额（本币）、合同总金额（原币）、变更后合同总金额（原币-含税）、变更后合同总金额（本位币-含税）赋默认值为：1000000000000000.00
        head.put("SFKJHT", erpContract.getIsFramework());
        // JNJW 境内/境外 枚举值 0：境内 1：境外
        head.put("JNJW", erpContract.getIsDomestic());
        // JZFWFSD 建筑服务发生地
        head.put("JZFWFSD", erpContract.getArchitectureService‌Place());
        // DDSKJE 达到收款条件金额
        head.put("DDSKJE", erpContract.getPayeeConditionAmount());

        Map<String, Object> req = new HashMap<>();
        req.put("header", head);
        erpSubmitReqDTO.setReq(req);

        Map<String, String> response = erpExternalApi.submitDataToErp(erpSubmitReqDTO);

        return response;
    }

    /**
     * 处理数据，区分新增和更新
     */
    private ProcessingResult processData(JSONArray dataArray, OftenEnum.FuncnrEnum funcnr) {
        String key = "erp" + funcnr.getFuncnr();
        Map<String, List<String>> numbers = myRedisConfig.numbers(dataArray, key, funcnr.getDatakey());
        List<String> allnumbers = numbers.get("all");
        List<String> comnumbers = numbers.get("com");
        List<ErpContractDO> toUpdate = new ArrayList<>();
        List<ErpContractDO> toInsert = new ArrayList<>();

        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataJson = dataArray.getJSONObject(i);
            if (dataJson != null) {
                String number = dataJson.getString("BUKRS").trim();
                if (number != null) {
                    ErpContractDO DO = new ErpContractDO();
//                    DO.setName(dataJson.getString("BUTXT"));
//                    DO.setNumber(number);
//                    DO.setCurrency(dataJson.getString("WAERS"));
                    if (comnumbers.contains(number)) {
                        // 更新
                        toUpdate.add(DO);
                    } else {
                        // 新增
                        toInsert.add(DO);
                    }
                }
            }
        }

        return new ProcessingResult(toUpdate, toInsert, key, allnumbers);
    }

    /**
     * 批量保存数据
     */
    private void saveData(ProcessingResult result) {
        // 批量新增和更新
        if (!result.toInsert.isEmpty()) {
            erpContractMapper.insertBatch(result.toInsert);
        }
        if (!result.toUpdate.isEmpty()) {
            erpContractMapper.updateBatch(result.toUpdate);
        }
        myRedisConfig.updateRedisCache(result.key, result.allnumbers);
    }

    /**
     * 数据处理结果封装类
     */
    private static class ProcessingResult {
        private final List<ErpContractDO> toUpdate;
        private final List<ErpContractDO> toInsert;
        private final String key;
        private final List<String> allnumbers;

        public ProcessingResult(List<ErpContractDO> toUpdate, List<ErpContractDO> toInsert, String key, List<String> allnumbers) {
            this.toUpdate = toUpdate;
            this.toInsert = toInsert;
            this.key = key;
            this.allnumbers = allnumbers;
        }
    }
    private AdminUserRespDTO getWorkId(){
        CommonResult<AdminUserRespDTO> user = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId());
        return user.getData();
    }
}