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.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.jwipc.exception.DaoException;
import com.jwipc.finance.convert.PaymentNoticeConvert;
import com.jwipc.finance.convert.PaymentNoticeDetailConvert;
import com.jwipc.finance.dto.*;
import com.jwipc.finance.entity.*;
import com.jwipc.finance.logic.PaymentNoticeLogic;
import com.jwipc.finance.logic.PaymentNoticeLogic;
import com.jwipc.finance.model.po.PaymentNoticePO;
import com.jwipc.finance.model.query.PaymentNoticeQuery;
import com.jwipc.finance.service.ICostMatchingPaymentNoticeRelationService;
import com.jwipc.finance.service.IPaymentNoticeApproveService;
import com.jwipc.finance.service.IPaymentNoticeDetailService;
import com.jwipc.finance.service.IPaymentNoticeService;
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.SupplierContactsDTO;
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.logic.BusinessAttachmentLogic;
import com.jwipc.sys.logic.KingdeeImageLogic;
import com.jwipc.sys.service.IBusinessAttachmentService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
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 PaymentNoticeLogicImpl implements PaymentNoticeLogic {
    private final IPaymentNoticeService paymentNoticeService;
    private final DeliverOrderClient deliverOrderClient;
    private final ICostMatchingPaymentNoticeRelationService costMatchingPaymentNoticeRelationService;
    private final IPaymentNoticeApproveService paymentNoticeApproveService;
    private final IPaymentNoticeDetailService paymentNoticeDetailService;
    private final IBusinessAttachmentService businessAttachmentService;
    private final BusinessAttachmentLogic businessAttachmentLogic;
    private final KingdeeImageLogic kingdeeImageLogic;
    private final PaymentNoticeConvert paymentNoticeConvert;
    private final PaymentNoticeDetailConvert paymentNoticeDetailConvert;
    private final SequenceClient sequenceClient;
    private final DictClient dictClient;
    private final PurchaseOrderClient purchaseOrderClient;
    private final SupplierClient supplierClient;
    @Override
    public PageView findByPage(PaymentNoticeQuery query) {
        final Page<PaymentNotice> dbPage = PageUtil.toPage(query);
        List<PaymentNoticePO> priceInfoAuditPOS = paymentNoticeService.findPageByQuery(dbPage, query);
        List<PaymentNoticeDTO> priceInfoAuditDTOS = paymentNoticeConvert.po2DTOList(priceInfoAuditPOS);
        for (PaymentNoticeDTO paymentNoticeDTO : priceInfoAuditDTOS) {
            Map costNoMap = paymentNoticeService.findCostNoById(paymentNoticeDTO.getId());
            if (ObjectUtil.isNotNull(costNoMap)) {
                paymentNoticeDTO.setNoticeDetailCode((String)costNoMap.get("noticeDetailCode"));
                paymentNoticeDTO.setCostMathingNo((String)costNoMap.get("costMathingNo"));
                paymentNoticeDTO.setCostMathingStatus((Integer)costNoMap.get("costMathingStatus"));
            }
        }
        return PageUtil.getPV(priceInfoAuditDTOS, dbPage.getTotal());
    }

    @Override
    @Transactional
    public void saveOrUpdate(PaymentNoticeParamDTO param) {
        if (param.getId() == null) {
            param.setCode(sequenceClient.createSequenceNo("payment_notice_no"));
            param.setStatus(1);
            param.setCreateTime(LocalDateTime.now());
            param.setCreateUser(LoginUtil.getUserId());
        } else {
            param.setUpdateTime(LocalDateTime.now());
            param.setUpdateUser(LoginUtil.getUserId());
            //删除明细
            paymentNoticeDetailService.remove(Wrappers.lambdaQuery(PaymentNoticeDetail.class).eq(PaymentNoticeDetail::getMainId,param.getId()));
        }
        if (StrUtil.isEmpty(param.getRemark())&&CollectionUtils.isNotEmpty(param.getDetailList())){
            param.setRemark(param.getDetailList().get(0).getCode()+"_运杂费_增值税_关税");
        }
          // 工厂编号与交易主体编号一致性校验
          // 1. 获取交易主体编号并提取纯编号（处理 (1000)xxx 格式）
        String companyCode = param.getCompanyCode();
        if (StrUtil.isBlank(companyCode)) {
            throw new DaoException("交易主体不能为空");
        }
        // 正则提取括号内的纯编号
        String pureCompanyCode = companyCode.replaceAll("^\\((\\d+)\\).*$", "$1");
        // 2. 遍历明细行校验工厂编号
        List<PaymentNoticeDetailDTO> detailList = param.getDetailList();
        if (CollectionUtils.isNotEmpty(detailList)) {
            for (int i = 0; i < detailList.size(); i++) {
                String entrustNo = detailList.get(i).getCode().toString();
                String factoryCode = deliverOrderClient.getFactoryCodesByEntrustNo(entrustNo);
                // 工厂编号为空则跳过校验
                if (StrUtil.isBlank(factoryCode)) {
                    continue;
                }
                // 工厂编号与交易主体编号不一致，抛出错误（提示行号，和前端一致）
                if (!pureCompanyCode.equals(factoryCode.trim())) {
                    throw new DaoException(String.format("第%d行明细的工厂编号【%s】与交易主体编号【%s】不一致",
                            i + 1, factoryCode.trim(), pureCompanyCode));
                }
            }
        }
        //保存主数据
        PaymentNotice priceInfoAudit = paymentNoticeConvert.DTO2Entity(param);
        paymentNoticeService.saveOrUpdate(priceInfoAudit);
        final List<PaymentNoticeDetailDTO> paymentNoticeDetailDTOS = param.getDetailList();
        //判断本次委托单号是否存在不一样的
        if (CollectionUtils.isNotEmpty(paymentNoticeDetailDTOS)) {
            String code = paymentNoticeDetailDTOS.get(0).getCode();
            paymentNoticeDetailDTOS.forEach(priceInfoAuditDetailDTO -> {
                if (!code.equals(priceInfoAuditDetailDTO.getCode())) {
                    throw new DaoException("明细中委托单号不一致");
                }
            });
            List<String> deliverOrderCodes = deliverOrderClient.getDevOrderCodesByEntrustNo(code);
            if (CollectionUtils.isEmpty(deliverOrderCodes)) {
                throw new DaoException("没有找到对应的委托单号");
            }
//            Map<String, List<PaymentNoticeDetailDTO>> ext = paymentNoticeDetailDTOS.stream()
//                    .collect(Collectors.groupingBy(PaymentNoticeDetailDTO::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);
        paymentNoticeDetailDTOS.forEach(priceInfoAuditDetailDTO -> {
            //判断明细单号是否在其他单据中存在
            PaymentNoticeDetail detail = paymentNoticeDetailService.getOne(Wrappers.lambdaQuery(PaymentNoticeDetail.class)
                    .eq(PaymentNoticeDetail::getCode,priceInfoAuditDetailDTO.getCode())
                    .eq(PaymentNoticeDetail::getDeleteFlag,0)
                    .ne(ObjectUtil.isNotNull(param.getId()), PaymentNoticeDetail::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();
        });
        paymentNoticeDetailService.saveBatch(paymentNoticeDetailConvert.dto2EntityList(paymentNoticeDetailDTOS));

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

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

        }
    }

    /**
     * 删除影像化
     *
     * @param id ID
     */
    @Override
    public void deleteImg(Long id) {
        //删除影像化
        PaymentNotice paymentNotice = paymentNoticeService.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(paymentNotice.getImgCode());
            kingdeeImageLogic.deleteAllImage(kingdeeInvoiceCloudImageDTO);
            paymentNoticeService.update(new LambdaUpdateWrapper<PaymentNotice>()
//                        .set(InvoicedApply::getImgCode,null)
                    .set(PaymentNotice::getImgTime, null)
                    .set(PaymentNotice::getImgUserId, null)
                    .eq(PaymentNotice::getId, id));
        }
    }

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

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

    @Override
    public PaymentNoticeDTO getById(Long id) {
        PaymentNotice paymentNotice = paymentNoticeService.getById(id);
        return paymentNoticeConvert.entity2DTO(paymentNotice);
    }

    @Override
    public List<PaymentNoticeDetailImportDTO> importData(MultipartFile file) {
        List<PaymentNoticeDetailImportDTO> cachedDataList = ListUtils.newArrayList();
        try {
            EasyExcel.read(file.getInputStream(), PaymentNoticeDetailImportDTO.class,
                    new ReadListener<PaymentNoticeDetailImportDTO>() {
                        @Override
                        public void invoke(PaymentNoticeDetailImportDTO 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(PaymentNoticeParamDTO param) {
        PaymentNotice paymentNotice = paymentNoticeService.getById(param.getId());
        paymentNotice.setStatus(param.getApproveStatus()==1?9:8);
        paymentNotice.setFinanceConfirmTime(LocalDateTime.now());
        paymentNotice.setFinanceConfirmUser(LoginUtil.getUserId());
        paymentNoticeService.updateById(paymentNotice);
        // 2.记录原因
        PaymentNoticeApprove approve = new PaymentNoticeApprove();
        approve.setMainId(paymentNotice.getId());
        approve.setMainNo(paymentNotice.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());
        paymentNoticeApproveService.save(approve);
        if (param.getApproveStatus()==0){
            this.deleteImg(param.getId());
        }
    }

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

        paymentNotice.setStatus(1);
        paymentNotice.setUpdateUser(LoginUtil.getUserId());
        paymentNotice.setUpdateTime(LocalDateTime.now());
        paymentNoticeService.updateById(paymentNotice);
        // 2.记录撤销原因
        PaymentNoticeApprove approve = new PaymentNoticeApprove();
        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());
        paymentNoticeApproveService.save(approve);
    }
}
