package com.jwipc.finance.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Strings;
import com.jwipc.constant.FlagConst;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.convert.CustomsDeclarationConvert;
import com.jwipc.finance.convert.CustomsDeclarationDetailConvert;
import com.jwipc.finance.dto.*;
import com.jwipc.finance.entity.*;
import com.jwipc.finance.logic.CustomsDeclarationLogic;
import com.jwipc.finance.model.po.CustomsDeclarationPO;
import com.jwipc.finance.model.query.CustomsDeclarationQuery;
import com.jwipc.finance.service.ICustomsDeclarationApproveService;
import com.jwipc.finance.service.ICustomsDeclarationDetailService;
import com.jwipc.finance.service.ICustomsDeclarationService;
import com.jwipc.finance.service.IPaymentMatchingCustomsDeclarationRelationService;
import com.jwipc.order.clent.dto.PurchaseDetailDTO;
import com.jwipc.order.clent.dto.PurchaseOrderDTO;
import com.jwipc.order.client.DeliverOrderClient;
import com.jwipc.order.client.PurchaseOrderClient;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.security.LoginUtil;
import com.jwipc.supplier.clent.dto.SupplierDTO;
import com.jwipc.supplier.client.SupplierClient;
import com.jwipc.sys.client.DictClient;
import com.jwipc.sys.client.SequenceClient;
import com.jwipc.sys.client.dto.DictDTO;
import com.jwipc.sys.dto.BusinessAttachmentDTO;
import com.jwipc.sys.dto.KingdeeInvoiceCloudImageDTO;
import com.jwipc.sys.entity.BusinessAttachment;
import com.jwipc.sys.entity.MsgTemplate;
import com.jwipc.sys.logic.BusinessAttachmentLogic;
import com.jwipc.sys.logic.KingdeeImageLogic;
import com.jwipc.sys.service.IBusinessAttachmentService;
import com.jwipc.util.DateUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author shenyang.ou
 * @date 2025/10/22 15:29
 * @desc
 */
@Service
@RequiredArgsConstructor
public class CustomsDeclarationLogicImpl implements CustomsDeclarationLogic {
    private final ICustomsDeclarationService customsDeclarationService;
    private final KingdeeImageLogic kingdeeImageLogic;
    private final ICustomsDeclarationApproveService customsDeclarationApproveService;
    private final ICustomsDeclarationDetailService customsDeclarationDetailService;
    private final IPaymentMatchingCustomsDeclarationRelationService paymentMatchingCustomsDeclarationRelationService;
    private final CustomsDeclarationConvert customsDeclarationConvert;
    private final CustomsDeclarationDetailConvert customsDeclarationDetailConvert;
    private final SequenceClient sequenceClient;
    private final DictClient dictClient;
    private final PurchaseOrderClient purchaseOrderClient;
    private final DeliverOrderClient deliverOrderClient;
    private final SupplierClient supplierClient;
    private final IBusinessAttachmentService businessAttachmentService;
    private final BusinessAttachmentLogic businessAttachmentLogic;
    @Override
    public PageView findByPage(CustomsDeclarationQuery query) {
        final Page<CustomsDeclaration> dbPage = PageUtil.toPage(query);
        List<CustomsDeclarationPO> priceInfoAuditPOS = customsDeclarationService.findPageByQuery(dbPage, query);
        List<CustomsDeclarationDTO> priceInfoAuditDTOS = customsDeclarationConvert.po2DTOList(priceInfoAuditPOS);

        if (CollUtil.isNotEmpty(priceInfoAuditDTOS)){
            //加载附件
            final Set<Long> ids = priceInfoAuditDTOS.stream().map(CustomsDeclarationDTO::getId).collect(Collectors.toSet());
            final List<BusinessAttachment> businessAttachmentList = businessAttachmentService.list(new LambdaQueryWrapper<BusinessAttachment>()
                    .in(BusinessAttachment::getBusinessId, ids).eq(BusinessAttachment::getBusinessTypeCode, "customs_declaration"));
            final Map<Long, List<Long>> businessAttachmentMap = businessAttachmentList.stream().collect(
                    Collectors.groupingBy(BusinessAttachment::getBusinessId,
                            Collectors.mapping(BusinessAttachment::getFileId, Collectors.toList())));
            for (CustomsDeclarationDTO dto : priceInfoAuditDTOS) {
                if (Objects.nonNull(businessAttachmentMap.get(dto.getId()))) {
                    dto.setAttachmentFiles("1");
                }
            }
        }
        return PageUtil.getPV(priceInfoAuditDTOS, dbPage.getTotal());
    }

    @Override
    @Transactional
    public void saveOrUpdate(CustomsDeclarationParamDTO param) {
        if (param.getId() == null) {
            param.setCode(sequenceClient.createSequenceNo("customs_declaration_no"));
            param.setStatus(1);
            param.setCreateTime(LocalDateTime.now());
            param.setCreateUser(LoginUtil.getUserId());
        } else {
            param.setStatus(1);
            param.setUpdateTime(LocalDateTime.now());
            param.setUpdateUser(LoginUtil.getUserId());
            //删除明细
            customsDeclarationDetailService.remove(Wrappers.lambdaQuery(CustomsDeclarationDetail.class).eq(CustomsDeclarationDetail::getMainId,param.getId()));
        }
        if (StrUtil.isEmpty(param.getRemark())&&CollectionUtils.isNotEmpty(param.getDetailList())){
            param.setRemark(param.getDetailList().get(0).getCode()+"_"+param.getSupplierCode()+"_报关单");
        }
        //保存主数据
        CustomsDeclaration priceInfoAudit = customsDeclarationConvert.DTO2Entity(param);
        customsDeclarationService.saveOrUpdate(priceInfoAudit);
        final List<CustomsDeclarationDetailDTO> customsDeclarationDetailDTOS = param.getDetailList();
        //提取订单号
        final List<String> poCodeList = customsDeclarationDetailDTOS.stream().map(CustomsDeclarationDetailDTO::getPoCode).toList();
        final List<PurchaseOrderDTO> purchaseOrderDTOS = purchaseOrderClient.getListByCodes(poCodeList);
        //判断poCodeList存在但purchaseOrderDTOS不存在的订单号
        final List<String> notExistPoCodeList = poCodeList.stream().filter(poCode -> purchaseOrderDTOS.stream().noneMatch(purchaseOrderDTO -> purchaseOrderDTO.getOrderCode().equals(poCode))).toList();
        if (CollUtil.isNotEmpty(notExistPoCodeList)) {
            throw new DaoException("订单号在系统中不存在：" + String.join(",", notExistPoCodeList));
        }
        //判断purchaseOrderDTOS中的公司是否和单头公司一致，不能存在多个，不满足则报错：具体的订单号的公司和单头不一致
        purchaseOrderDTOS.forEach(purchaseOrderDTO -> {
            if (!purchaseOrderDTO.getCompanyCode().equals(param.getCompanyCode())) {
                throw new DaoException("订单号：" + purchaseOrderDTO.getOrderCode() + "的交易主体不一致：" + purchaseOrderDTO.getCompanyCode() + "与单头易主体不一致。");
            }
        });

        customsDeclarationDetailDTOS.forEach(priceInfoAuditDetailDTO -> {
            if (StrUtil.isNotEmpty(priceInfoAuditDetailDTO.getPoCode())&& StrUtil.isNotEmpty(priceInfoAuditDetailDTO.getMaterialCode())){
                PurchaseDetailDTO purchaseDetailDTO = purchaseOrderClient.getOrderDetailByCodeAndMaterialCode(priceInfoAuditDetailDTO.getPoCode(),priceInfoAuditDetailDTO.getMaterialCode());
                if (ObjectUtil.isNull(purchaseDetailDTO)){
                    throw new DaoException("订单号：" + priceInfoAuditDetailDTO.getPoCode() + "的物料：" + priceInfoAuditDetailDTO.getMaterialCode() + "在系统中不存在");
                }
            }
        });

        //判断本次委托单号是否重复
        if (CollectionUtils.isNotEmpty(customsDeclarationDetailDTOS)) {
            String code = customsDeclarationDetailDTOS.get(0).getCode();
            customsDeclarationDetailDTOS.forEach(priceInfoAuditDetailDTO -> {
                if (!code.equals(priceInfoAuditDetailDTO.getCode())) {
                    throw new DaoException("明细中委托单号不一致");
                }
            });
            //扣款类型不需要校验
            if (param.getType() != 2) {
                List<String> deliverOrderCodes = deliverOrderClient.getDevOrderCodesByEntrustNo(code);
                if (CollectionUtils.isEmpty(deliverOrderCodes)) {
                    throw new DaoException("没有找到对应的委托单号");
                }
            }
//            Map<String, List<CustomsDeclarationDetailDTO>> ext = customsDeclarationDetailDTOS.stream()
//                    .collect(Collectors.groupingBy(CustomsDeclarationDetailDTO::getCode))
//                    .entrySet().stream()
//                    .filter(entry -> entry.getValue().size() > 1)
//                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
//            if (ObjectUtil.isNotNull(ext)) {
//                ext.forEach((key, value) -> {
//                    throw new DaoException("明细中委托单号：" + key + "重复" + value.size() + "条，请删除其中" + (value.size() - 1) + "条");
//                });
//            }
        }

        AtomicInteger index = new AtomicInteger(1);
        customsDeclarationDetailDTOS.forEach(priceInfoAuditDetailDTO -> {
            //判断明细单号是否在其他单据中存在
            CustomsDeclarationDetail detail = customsDeclarationDetailService.getOne(Wrappers.lambdaQuery(CustomsDeclarationDetail.class)
                    .eq(CustomsDeclarationDetail::getCode,priceInfoAuditDetailDTO.getCode())
                    .eq(CustomsDeclarationDetail::getDeleteFlag,0)
                    .ne(ObjectUtil.isNotNull(param.getId()), CustomsDeclarationDetail::getMainId, param.getId()).last(" limit 1"));
            if (ObjectUtil.isNotNull(detail)){
                throw new DaoException("明细中委托单号：" + priceInfoAuditDetailDTO.getCode() + "在报关明细单号："+detail.getMainCode()+"中已存在");
            }
            priceInfoAuditDetailDTO.setId(null);
            priceInfoAuditDetailDTO.setMainCode(priceInfoAudit.getCode());
            priceInfoAuditDetailDTO.setMainId(priceInfoAudit.getId());
            priceInfoAuditDetailDTO.setItemNo(String.valueOf(index));
            index.getAndIncrement();
        });
        customsDeclarationDetailService.saveBatch(customsDeclarationDetailConvert.dto2EntityList(customsDeclarationDetailDTOS));

        // 附件关系
        businessAttachmentService.remove(Wrappers.lambdaQuery(BusinessAttachment.class)
                .eq(BusinessAttachment::getBusinessId, priceInfoAudit.getId())
                .eq(BusinessAttachment::getBusinessTypeCode, "customs_declaration")
        );
        List<BusinessAttachmentDTO> businessAttachmentDTOList = param.getBusinessAttachmentDTOList();
        businessAttachmentDTOList.forEach(item -> {
            item.setId(null);
            item.setDeleteFlag(0);
            item.setBusinessId(priceInfoAudit.getId());
            item.setBusinessTypeCode("customs_declaration");
        });
        businessAttachmentLogic.saveAttachment(businessAttachmentDTOList);
    }

    /**
     * 影像化
     *
     * @param id ID
     */
    @Override
    public void toImg(Long id) {
        CustomsDeclaration customsDeclaration = customsDeclarationService.getById(id);
        //影像化
        List<BusinessAttachmentDTO> accountStatementAttachments = businessAttachmentLogic.getListByBusinessId(id);
        if (CollUtil.isNotEmpty(accountStatementAttachments)) {
            KingdeeInvoiceCloudImageDTO kingdeeInvoiceCloudImageDTO = new KingdeeInvoiceCloudImageDTO();
            kingdeeInvoiceCloudImageDTO.setImageCode(StrUtil.isNotEmpty(customsDeclaration.getImgCode()) ? customsDeclaration.getImgCode() : sequenceClient.createSequenceNo("image_code"));
            if (CollUtil.isNotEmpty(accountStatementAttachments)) {
                kingdeeInvoiceCloudImageDTO.setBusinessAttachmentList(accountStatementAttachments);
                KingdeeInvoiceCloudImageDTO result = kingdeeImageLogic.pushImage(kingdeeInvoiceCloudImageDTO);
                customsDeclarationService.update(new LambdaUpdateWrapper<CustomsDeclaration>()
                        .set(CustomsDeclaration::getImgCode, result.getImageCode())
                        .set(CustomsDeclaration::getImgTime, LocalDateTime.now())
                        .set(CustomsDeclaration::getImgUserId, LoginUtil.getUserId())
                        .eq(CustomsDeclaration::getId, id));
            }

        }
    }

    /**
     * 删除影像化
     *
     * @param id ID
     */
    @Override
    public void deleteImg(Long id) {
        //删除影像化
        CustomsDeclaration customsDeclaration = customsDeclarationService.getById(id);
        List<BusinessAttachment> businessAttachments = businessAttachmentService.list(new LambdaQueryWrapper<BusinessAttachment>().eq(BusinessAttachment::getBusinessId, id));
        if (CollUtil.isNotEmpty(businessAttachments)) {
            //过滤出accountStatementAttachments中存在imageCode的数据
            KingdeeInvoiceCloudImageDTO kingdeeInvoiceCloudImageDTO = new KingdeeInvoiceCloudImageDTO();
            kingdeeInvoiceCloudImageDTO.setImageCode(customsDeclaration.getImgCode());
            kingdeeImageLogic.deleteAllImage(kingdeeInvoiceCloudImageDTO);
            customsDeclarationService.update(new LambdaUpdateWrapper<CustomsDeclaration>()
//                        .set(InvoicedApply::getImgCode,null)
                    .set(CustomsDeclaration::getImgTime, null)
                    .set(CustomsDeclaration::getImgUserId, null)
                    .eq(CustomsDeclaration::getId, id));
        }
    }

    @Override
    public void remove(Long id) {
        customsDeclarationService.removeById(id);
        //删除明细
        customsDeclarationDetailService.remove(Wrappers.lambdaQuery(CustomsDeclarationDetail.class).eq(CustomsDeclarationDetail::getMainId,id));
        businessAttachmentService.remove(Wrappers.lambdaQuery(BusinessAttachment.class).eq(BusinessAttachment::getBusinessId, id));
    }

    @Override
    @Transactional
    public void pushConfirm(Long id) {
        CustomsDeclaration customsDeclaration = customsDeclarationService.getById(id);
        customsDeclaration.setStatus(7);
        customsDeclaration.setUpdateTime(LocalDateTime.now());
        customsDeclaration.setUpdateUser(LoginUtil.getUserId());
        customsDeclarationService.updateById(customsDeclaration);
        this.toImg(id);
    }

    @Override
    public CustomsDeclarationDTO getById(Long id) {
        CustomsDeclaration customsDeclaration = customsDeclarationService.getById(id);
        return customsDeclarationConvert.entity2DTO(customsDeclaration);
    }

    @Override
    public List<CustomsDeclarationDetailImportDTO> importData(MultipartFile file) {
        List<CustomsDeclarationDetailImportDTO> cachedDataList = ListUtils.newArrayList();
        try {
            EasyExcel.read(file.getInputStream(), CustomsDeclarationDetailImportDTO.class,
                    new ReadListener<CustomsDeclarationDetailImportDTO>() {
                        @Override
                        public void invoke(CustomsDeclarationDetailImportDTO data, AnalysisContext context) {
                            final String materialCode = data.getMaterialCode();
                            final String poCode = data.getPoCode();
                            String codeDateStr = data.getCodeDateStr();
                            if (StrUtil.isNotEmpty(codeDateStr)) {
                                try {
                                    codeDateStr = codeDateStr.replaceAll("/", "-");
                                    Date codeDate = DateUtil.parse(codeDateStr, "yyyy-MM-dd");
                                    data.setCodeDate(LocalDateTimeUtil.parseDate(DateUtil.format(codeDate,"yyyy-MM-dd"), "yyyy-MM-dd"));
                                } catch (Exception e) {
                                    throw new DaoException("请输入正确的单据日期；如：2025/11/11");
                                }
                            }
                            if (StrUtil.isNotEmpty(poCode)) {
                                PurchaseOrderDTO purchaseOrderDTO =  purchaseOrderClient.getOrderByCode(poCode);
                                if (ObjectUtil.isNull(purchaseOrderDTO)){
                                    throw new DaoException(StrUtil.format("采购订单编码:{}在系统中不存在",poCode));
                                }else {
                                    data.setSupplierCode(purchaseOrderDTO.getSupplierErpCode());
                                    data.setSupplierName(purchaseOrderDTO.getSupplierName());
                                    SupplierDTO supplierDTO = supplierClient.getSupplierByCode(purchaseOrderDTO.getSupplierErpCode());
                                    if (ObjectUtil.isNotNull(supplierDTO)){
                                        data.setSupplierName(supplierDTO.getShortName());
                                    }
                                }
                            }

                            if (StrUtil.isNotEmpty(data.getCurrencyCode())) {
                                DictDTO dictDTO = dictClient.getDictByTypeAndCode("currency",data.getCurrencyCode());
                                if (ObjectUtil.isNull(dictDTO)){
                                    throw new DaoException(StrUtil.format("币种:{}在系统中不存在",data.getCurrencyCode()));
                                }else {
                                    data.setCurrencyCode(dictDTO.getCode());
                                }
                            }
                            cachedDataList.add(data);
                        }
                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        }
                    }).sheet().doRead();
        } catch (IOException e) {
            throw new DaoException("导入失败！");
        }
        return cachedDataList;
    }

    @Override
    @Transactional
    public void financeConfirm(CustomsDeclarationParamDTO param) {
        CustomsDeclaration customsDeclaration = customsDeclarationService.getById(param.getId());
        customsDeclaration.setStatus(param.getApproveStatus()==1?9:8);
        customsDeclaration.setFinanceConfirmTime(LocalDateTime.now());
        customsDeclaration.setFinanceConfirmUser(LoginUtil.getUserId());
        customsDeclarationService.updateById(customsDeclaration);
        // 2.记录原因
        CustomsDeclarationApprove approve = new CustomsDeclarationApprove();
        approve.setMainId(customsDeclaration.getId());
        approve.setMainNo(customsDeclaration.getCode());
        approve.setApproveResult(param.getApproveStatus());
        approve.setApproveOpinion(param.getApproveOpinion());
        approve.setApproveUserId(LoginUtil.getUserId());
        approve.setApproveUserCode(LoginUtil.getAccount());
        approve.setApproveUserName(LoginUtil.getName());
        // 财务节点
        approve.setApproveNode(2);
        approve.setApproveTime(LocalDateTime.now());
        customsDeclarationApproveService.save(approve);
        if (param.getApproveStatus()==0){
            this.deleteImg(param.getId());
        }

    }

    @Override
    public List<String> financeConfirmCheck(CustomsDeclarationParamDTO param) {
        List<String> msgs = new ArrayList<>();
        CustomsDeclaration customsDeclaration = customsDeclarationService.getById(param.getId());
        List<CustomsDeclarationDetail> details = customsDeclarationDetailService.list(new LambdaQueryWrapper<CustomsDeclarationDetail>()
                .eq(CustomsDeclarationDetail::getMainId, customsDeclaration.getId()).eq(CustomsDeclarationDetail::getDeleteFlag, 0));
        if (CollUtil.isNotEmpty(details)){
            for (CustomsDeclarationDetail detail : details){
                PurchaseOrderDTO purchaseOrderDTO = purchaseOrderClient.getOrderByCode(detail.getPoCode());
                if (ObjectUtil.isNotNull(purchaseOrderDTO)){
                    if (StrUtil.isNotEmpty(purchaseOrderDTO.getSupplierCode2())&&!purchaseOrderDTO.getSupplierCode2().equals(customsDeclaration.getSupplierCode())){
                        msgs.add(StrUtil.format("采购订单{}的报关供应商与报关单中的代理商不一致，请确认",detail.getPoCode()));
                    }
                }
            }
        }
        return msgs;
    }

    @Override
    public void revokeFinConfirmed(Long id, String revokeReason) {
        final CustomsDeclaration paymentNotice = customsDeclarationService.getById(id);
        if(null == paymentNotice){
            throw new DaoException("系统未找到相应的单据信息");
        }
        if(9 != paymentNotice.getStatus()){
            throw new DaoException("不能进行撤销操作, 请检查单据状态");
        }
        List<CustomsDeclarationDetail> details = customsDeclarationDetailService.list(new LambdaQueryWrapper<CustomsDeclarationDetail>()
                .eq(CustomsDeclarationDetail::getMainId, paymentNotice.getId()).eq(CustomsDeclarationDetail::getDeleteFlag, 0));
        for (CustomsDeclarationDetail detail : details){
            PaymentMatchingCustomsDeclarationRelation relation = paymentMatchingCustomsDeclarationRelationService.getOne(new LambdaQueryWrapper<PaymentMatchingCustomsDeclarationRelation>()
                    .eq(PaymentMatchingCustomsDeclarationRelation::getCustomsDeclarationDetailId, detail.getId())
                    .eq(PaymentMatchingCustomsDeclarationRelation::getDeleteFlag, 0));
            if (ObjectUtil.isNotNull(relation)){
                throw new DaoException("报关单: " + paymentNotice.getCode() + "不能被撤销，明细已被货款匹配单："+relation.getMainCode()+"使用");
            }
        }

        paymentNotice.setStatus(1);
        paymentNotice.setUpdateUser(LoginUtil.getUserId());
        paymentNotice.setUpdateTime(LocalDateTime.now());
        customsDeclarationService.updateById(paymentNotice);
        // 2.记录撤销原因
        CustomsDeclarationApprove approve = new CustomsDeclarationApprove();
        approve.setMainId(paymentNotice.getId());
        approve.setMainNo(paymentNotice.getCode());
        approve.setApproveResult(3);
        approve.setApproveOpinion(revokeReason);
        approve.setApproveUserId(LoginUtil.getUserId());
        approve.setApproveUserCode(LoginUtil.getAccount());
        approve.setApproveUserName(LoginUtil.getName());
        // 撤销只能由采购操作
        approve.setApproveNode(2);
        approve.setApproveTime(LocalDateTime.now());
        customsDeclarationApproveService.save(approve);
    }
}
