package com.jwipc.order.client.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
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.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.jwipc.constant.FlagConst;
import com.jwipc.order.clent.dto.*;
import com.jwipc.order.client.PurchaseOrderClient;
import com.jwipc.order.client.convert.PurchaseOrderClientConvert;
import com.jwipc.order.client.convert.PurchaseOrderDetailClientConvert;
import com.jwipc.order.client.convert.PurchaseOrderDevPlanClientConvert;
import com.jwipc.order.convert.OrderAttachmentConvert;
import com.jwipc.order.entity.PurchaseOrder;
import com.jwipc.order.entity.PurchaseOrderDetail;
import com.jwipc.order.entity.PurchaseOrderDevPlan;
import com.jwipc.order.model.po.OrderAttachmentPO;
import com.jwipc.order.model.po.PurchaseOrderPO;
import com.jwipc.order.model.query.PurchaseOrderQuery;
import com.jwipc.order.service.IOrderAttachmentService;
import com.jwipc.order.service.IPurchaseOrderDetailService;
import com.jwipc.order.service.IPurchaseOrderDevPlanService;
import com.jwipc.order.service.IPurchaseOrderService;
import com.jwipc.sys.entity.Attachment;
import com.jwipc.sys.logic.FileLogic;
import com.jwipc.sys.service.IAttachmentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.time.LocalDateTime;
import java.util.*;

import static com.baomidou.dynamic.datasource.support.DdConstants.SLAVE;

/**
 * <p>
 *
 * </p>
 *
 * @author wt
 * @version 1.0
 * @since 2024/3/8
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PurchaseOrderClientImpl implements PurchaseOrderClient {

    private final IPurchaseOrderService purchaseOrderService;
    private final IPurchaseOrderDetailService purchaseOrderDetailService;
    private final PurchaseOrderClientConvert purchaseOrderClientConvert;
    private final PurchaseOrderDetailClientConvert purchaseOrderDetailClientConvert;
    private final IPurchaseOrderDevPlanService purchaseOrderDevPlanService;
    private final PurchaseOrderDevPlanClientConvert purchaseOrderDevPlanClientConvert;
    private final IAttachmentService attachmentService;
    private final FileLogic fileLogic;

    private final IOrderAttachmentService orderAttachmentService;
    private final OrderAttachmentConvert orderAttachmentConvert;


    /**
     * 查询采购订单数据
     *
     * @param orderCode 采购订单代码
     * @return 采购订单数据
     */
    public PurchaseOrderDTO getOrderByCode(String orderCode) {
        PurchaseOrder purchaseOrder = purchaseOrderService.getOne(
                Wrappers.lambdaQuery(PurchaseOrder.class).eq(PurchaseOrder::getOrderCode, orderCode).last(" limit 1"));
        return purchaseOrderClientConvert.entityToDTO(purchaseOrder);
    }

    @Override
    public List<PurchaseOrderDTO> getOrderListById(Long id) {
        PurchaseOrder byId = purchaseOrderService.getById(id);
        if(byId != null){
         if(StringUtils.isNotEmpty(byId.getBatchNo())){
             List<PurchaseOrder> purchaseOrderList = purchaseOrderService.list(Wrappers.lambdaQuery(PurchaseOrder.class).eq(PurchaseOrder::getBatchNo, byId.getBatchNo()));
             return purchaseOrderClientConvert.entityToDTOList(purchaseOrderList);
         }
        }
        return null;
    }

    /**
     * 查询采购订单明细数据
     *
     * @param orderCode   采购订单代码
     * @param orderRow    采购订单行项目
     * @param factoryCode 工厂
     * @return 采购订单明细数据
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @DS(SLAVE)
    public PurchaseDetailDTO getOrderDetailByCodeAndItemNoAndFactoryCode(String orderCode, String orderRow,
                                                                         String factoryCode)
    {
        PurchaseOrderDetail purchaseOrderDetail = purchaseOrderDetailService.getOne(
                Wrappers.lambdaQuery(PurchaseOrderDetail.class).eq(PurchaseOrderDetail::getOrderCode, orderCode)
                        .eq(PurchaseOrderDetail::getFactoryCode, factoryCode)
                        .eq(PurchaseOrderDetail::getOrderRow, orderRow).last(" limit 1"));
        return purchaseOrderDetailClientConvert.entityToDTO(purchaseOrderDetail);
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @DS(SLAVE)
    public PurchaseDetailDTO getOrderDetailByCodeAndItemNo(String orderCode, String orderRow)
    {
        PurchaseOrderDetail purchaseOrderDetail = purchaseOrderDetailService.getOne(
                Wrappers.lambdaQuery(PurchaseOrderDetail.class).eq(PurchaseOrderDetail::getOrderCode, orderCode)
                        .eq(PurchaseOrderDetail::getOrderRow, orderRow).last(" limit 1"));
        return purchaseOrderDetailClientConvert.entityToDTO(purchaseOrderDetail);
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @DS(SLAVE)
    public PurchaseDetailDTO getOrderDetailByCodeAndMaterialCode(String orderCode, String materialCode)
    {
        PurchaseOrderDetail purchaseOrderDetail = purchaseOrderDetailService.getOne(
                Wrappers.lambdaQuery(PurchaseOrderDetail.class).eq(PurchaseOrderDetail::getOrderCode, orderCode)
                        .eq(PurchaseOrderDetail::getMaterialCode, materialCode).last(" limit 1"));
        return purchaseOrderDetailClientConvert.entityToDTO(purchaseOrderDetail);
    }

    /**
     * 查询采购订单明细数据
     *
     * @param detailQuery 查询条件
     * @return
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @DS(SLAVE)
    public List<PurchaseDetailDTO> getOrderDetailInfo(List<PurchaseDetailDTO> detailQuery) {
        List<PurchaseOrderDetail> query = purchaseOrderDetailClientConvert.dtoToEntityList(detailQuery);
        List<PurchaseOrderDetail> details = purchaseOrderDetailService.getPurchaseOrderDetailListByList(query);
        return purchaseOrderDetailClientConvert.entityToDtoList(details);
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @DS(SLAVE)
    public void updatePurchaseDetail(List<UpdateOrderDetailDTO> updateOrderDetailDTOS,
                                     List<PurchaseOrderDevPlanDTO> planDTOS)
    {

        for (UpdateOrderDetailDTO updateOrderDetailDTO : updateOrderDetailDTOS) {
            final Integer finishFlag = updateOrderDetailDTO.getFinishFlag();
            final FlagConst flag = FlagConst.getFlag(finishFlag);
            final LambdaUpdateWrapper<PurchaseOrderDetail> wrapper = new LambdaUpdateWrapper<PurchaseOrderDetail>()
                    .set(PurchaseOrderDetail::getReceivedNum, updateOrderDetailDTO.getReceivedNum())
                    .setSql("no_clear_num=num-received_num")
                    .set(PurchaseOrderDetail::getFinishFlag, flag.getLabel())
                    .eq(PurchaseOrderDetail::getOrderCode, updateOrderDetailDTO.getOrderCode())
                    .eq(PurchaseOrderDetail::getOrderRow, updateOrderDetailDTO.getOrderRow())
                    .eq(PurchaseOrderDetail::getFactoryCode, updateOrderDetailDTO.getFactoryCode());
            purchaseOrderDetailService.update(wrapper);
        }
        List<PurchaseOrderDevPlan> purchaseOrderDevPlanList = Lists.newArrayList();
        for (PurchaseOrderDevPlanDTO planDTO : planDTOS) {
            final PurchaseOrderDevPlan db = purchaseOrderDevPlanService.getOne(
                    new LambdaQueryWrapper<PurchaseOrderDevPlan>()
                            .eq(PurchaseOrderDevPlan::getPurchaseOrder, planDTO.getPurchaseOrder())
                            .eq(PurchaseOrderDevPlan::getLineItem, planDTO.getLineItem())
                            .eq(PurchaseOrderDevPlan::getScheduleLine, planDTO.getScheduleLine()), false);
            PurchaseOrderDevPlan orderDevPlan = purchaseOrderDevPlanClientConvert.dto2entity(planDTO);
            if (Objects.nonNull(db)) {
                orderDevPlan.setId(db.getId());
            }
            purchaseOrderDevPlanList.add(orderDevPlan);
        }
        if (CollUtil.isNotEmpty(purchaseOrderDevPlanList)) {
            try {
                purchaseOrderDevPlanService.saveOrUpdateBatch(purchaseOrderDevPlanList);
            } catch (DuplicateKeyException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void updateOrderFin(Long id) {
        purchaseOrderService.update(new LambdaUpdateWrapper<>(PurchaseOrder.class)
                .eq(PurchaseOrder::getId, id)
                .notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"))
                .set(PurchaseOrder::getAttachmentType,1)
                .set(PurchaseOrder::getFileState, FlagConst.Y.getCode())
                .set(PurchaseOrder::getFinConf, FlagConst.Y.getCode()));
    }

    @Override
    public void updateFinConf(Set<String> orderCode, Long userId) {
        purchaseOrderService.update(new LambdaUpdateWrapper<>(PurchaseOrder.class)
                .in(PurchaseOrder::getOrderCode, orderCode)
//                .notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"))
                .set(PurchaseOrder::getFinTime,LocalDateTime.now())
                .set(PurchaseOrder::getFinUserId, userId)
                .set(PurchaseOrder::getFinConf, FlagConst.Y.getCode()));
    }

    /**
     * 修改订单财务确认状态和附件回签状态
     * @param id
     */
    @Override
    public void updateOrderFinAndFileState(List<Long> id,Integer finConf,Integer fileState) {
        LambdaUpdateWrapper<PurchaseOrder> purchaseOrderLambdaUpdateWrapper = new LambdaUpdateWrapper<>(PurchaseOrder.class);
        purchaseOrderLambdaUpdateWrapper.in(PurchaseOrder::getId, id)
                .notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"));
        if(Objects.nonNull(fileState)){
            purchaseOrderLambdaUpdateWrapper.set(PurchaseOrder::getFileState, fileState);
        }
        if(Objects.nonNull(finConf)){
            purchaseOrderLambdaUpdateWrapper.set(PurchaseOrder::getFinConf, finConf);
        }
        purchaseOrderService.update(purchaseOrderLambdaUpdateWrapper);




    }

    /**
     * 修改订单附件回传状态
     * @param id
     */
    @Override
    public void updateOrderFileState(List<Long> id) {
        purchaseOrderService.update(new LambdaUpdateWrapper<>(PurchaseOrder.class)
                .in(PurchaseOrder::getId, id)
                        .notIn(PurchaseOrder::getOrderTypeCode, Arrays.asList("Z003","Z004","Z005","Z006","Z007","Z009","Z010"))
                        .set(PurchaseOrder::getFileState, FlagConst.N.getCode())
                );
    }
    @DS(SLAVE)
    @Override
    public List<PurchaseDetailDTO> getOrderDetaiBySupplierCodeAndMaterial(String supplierCode, List<String> material) {
        LambdaQueryWrapper<PurchaseOrderDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(PurchaseOrderDetail :: getMaterialCode,PurchaseOrderDetail :: getSupplierErpCode);
        queryWrapper.eq(PurchaseOrderDetail::getSupplierErpCode, supplierCode);
        queryWrapper.in(PurchaseOrderDetail::getMaterialCode, material);
        List<PurchaseOrderDetail> list = purchaseOrderDetailService.list(queryWrapper);
        return purchaseOrderDetailClientConvert.entityToDtoList(list);
    }

    @Override
    public String findMonthNGconfirmOrderList(String accountStatementId,String year, String month, String supplierCode) {
        PurchaseOrderQuery query = new PurchaseOrderQuery();
        query.setSupplierCode(supplierCode);
        Calendar calendar = Calendar.getInstance();
        //对账单当月的采购数据不计算在内 邓京术 2025-07-08
        calendar.set(Integer.parseInt(year),Integer.parseInt(month) - 2,1);
        calendar.set(Integer.parseInt(year),Integer.parseInt(month) - 2, calendar.getActualMaximum(Calendar.DAY_OF_MONTH),23, 59, 59);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
        query.setEffectiveDate(localDateTime);
        List<PurchaseOrderPO> purchaseOrderPOS = purchaseOrderService.findMonthNGconfirmOrderList(query);
        StringBuilder sb = new StringBuilder("");
        //判断是否有供应商未确认的订单或未签署的订单 邓京术 2025-06-05
        if (Objects.nonNull(purchaseOrderPOS) && purchaseOrderPOS.size() > 0) {
            String title = purchaseOrderPOS.get(0).getSupplierName() + "仍有未确认的采购订单，单号：";
            Map<String,String> orderCodeMap = Maps.newHashMap();
            //state == 6 待供应商确认 8 收货完成   finconf ！= 1 智微财务未确认
            purchaseOrderPOS.stream().forEach(item -> {
                boolean flag = true;
                if (item.getState() == 6 || item.getState() == 8 || item.getFinConf() != 1) {
                    flag = false;
                }
                if (!flag && !orderCodeMap.keySet().contains(item.getOrderCode())) {
                    sb.append(item.getOrderCode() + ",");
                    orderCodeMap.put(item.getOrderCode(), item.getOrderCode());
                }
            });
            if (sb.toString().length() > 0) {
                //行去掉校验，等业务通知。
                return title + sb.toString().substring(0,sb.toString().length() - 1);
            }
            return null;
        } else {
            return null;
        }
    }

    /**
     * 查询pdf文件的总页数
     * @param fileId
     * @return
     */
    public Integer getEsignTotalPage(Long fileId) {
        Attachment attachment = attachmentService.getById(fileId);
        //生成购销合同的方式不一样，从数据库取名字也有所不一样，后续要保持一致， 邓京术 2025-07-09
        File file = new File(StrUtil.concat(false, fileLogic.getFilePath(), attachment.getFilePath().substring(0,attachment.getFilePath().lastIndexOf("/") + 1), attachment.getFileName()));
        if (null == file) {
            file = new File(StrUtil.concat(false, fileLogic.getFilePath(), "", attachment.getFilePath()));
        }
        log.info(file.getPath() +"==============" + file.getName());

        // 再次打开文件并进行处理
        // 使用 PdfReader 和 PdfWriter 进行处理
        InputStream inputStream = null;
        PdfWriter writer = null;
        PdfReader reader = null;
        try {
            inputStream = new FileInputStream(file);
            reader = new PdfReader(inputStream);
            writer = new PdfWriter(file);
            try (PdfDocument pdfDoc = new PdfDocument(reader, writer)) {
                int numberOfPages = pdfDoc.getNumberOfPages();
                return numberOfPages;
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 通过供应商code和工厂code查询所有有效的采购订单信息
     * @param
     * @return
     */
    @DS(SLAVE)
    @Override
    public List<PurchaseDetailDTO> getOrderDetailBysupplierCodeAndFactoryCode(String supplierCode,String factoryCode,String orderCode) {
        List<PurchaseOrderDetail> supplierCodeAndFactoryCode = purchaseOrderDetailService.findBysupplierCodeAndFactoryCode(supplierCode, factoryCode,orderCode);
        return purchaseOrderDetailClientConvert.entityToDtoList(supplierCodeAndFactoryCode);
    }

    @Override
    public List<PurchaseOrderDTO> getListByCodes( List<String> nos) {
        final LambdaQueryWrapper<PurchaseOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(PurchaseOrder::getOrderCode, nos);
        List<PurchaseOrder> list = purchaseOrderService.list(queryWrapper);
        return purchaseOrderClientConvert.entityToDTOList(list);
    }

    @Override
    public List<PurchaseOrderAttachmentDTO> getAttachmentList(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        Set<String> stringSet = new HashSet<>();
        stringSet.addAll(ids);
        final List<OrderAttachmentPO> list = orderAttachmentService.findPageByIds(stringSet);
        List<PurchaseOrderAttachmentDTO> attachmentDTOS = orderAttachmentConvert.po2puDtos(list);
        return attachmentDTOS;
    }
}
