package com.jwipc.finance.logic.impl;

import cn.hutool.core.collection.CollUtil;
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.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Strings;
import com.jwipc.constant.DictCode;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.convert.InvoicedReceiptConvert;
import com.jwipc.finance.dto.AccountStatementDTO;
import com.jwipc.finance.dto.InvoicedReceiptDTO;
import com.jwipc.finance.dto.InvoicedReceiptImportDTO;
import com.jwipc.finance.entity.AccountStatement;
import com.jwipc.finance.entity.InvoicedReceipt;
import com.jwipc.finance.entity.ReceiveVoucher;
import com.jwipc.finance.logic.InvoicedReceiptLogic;
import com.jwipc.finance.model.po.AccountStatementPO;
import com.jwipc.finance.model.po.InvoicedReceiptPO;
import com.jwipc.finance.model.query.InvoicedDetailQuery;
import com.jwipc.finance.service.IInvoicedReceiptService;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.security.dto.CurrentUserDTO;
import com.jwipc.sys.client.DictClient;
import com.jwipc.sys.client.dto.DictDTO;
import com.jwipc.sys.client.dto.ProductGroupDTO;
import com.jwipc.sys.client.dto.ProductInfoDTO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shenyang.ou
 * @date 2024/3/5 13:27
 * @desc
 */
@Service
@RequiredArgsConstructor
public class InvoicedReceiptLogicImpl implements InvoicedReceiptLogic {
    private final InvoicedReceiptConvert invoicedReceiptConvert;
    private final IInvoicedReceiptService invoicedReceiptService;
    private final DictClient dictClient;

    /**
     * 根据开票申请单ID获取关联发票数据
     *
     * @param iaId 开票申请单ID
     * @return 关联发票数据
     */
    @Override
    public List<InvoicedReceiptDTO> getInvoiceReceiptListByIaId(Long iaId) {
        List<InvoicedReceiptPO> invoicedReceiptPOS = invoicedReceiptService.getInvoiceReceiptListByIaId(iaId);;
        return invoicedReceiptConvert.po2DTOList(invoicedReceiptPOS);
    }

    /**
     * 关联或取消关联发票
     *
     * @param invoicedReceiptData 发票数据
     * @param iaId                开票申请单ID
     * @param currentUser         当前用户
     */
    @Override
    public void operateInvoice(List<InvoicedReceiptDTO> invoicedReceiptData, Long iaId, CurrentUserDTO currentUser) {
        if (CollUtil.isNotEmpty(invoicedReceiptData)) {
            invoicedReceiptData.forEach(e -> e.setIaId(iaId));
            List<Long> allIds = invoicedReceiptData.stream().map(InvoicedReceiptDTO::getId).filter(Objects::nonNull).collect(Collectors.toList());
            List<InvoicedReceipt> existList = invoicedReceiptService.list(Wrappers.lambdaQuery(InvoicedReceipt.class).eq(InvoicedReceipt::getIaId,iaId));
            List<Long> exitIds = existList.stream().map(InvoicedReceipt::getId).collect(Collectors.toList());
            List<Long> removeIds = exitIds.stream().filter(f -> !allIds.contains(f)).collect(Collectors.toList());

            // 删除
            if (CollUtil.isNotEmpty(removeIds)) {
                invoicedReceiptService.removeBatchByIds(removeIds);
            }
            //判断本次发票号码是否重复
            List<InvoicedReceiptDTO> nonNullNameList = invoicedReceiptData.stream()
                    .filter(p -> StringUtils.isNotEmpty(p.getInvoiceNumber()))
                    .toList();
            if(CollectionUtils.isNotEmpty(nonNullNameList)){
                Map<String, List<InvoicedReceiptDTO>> ext = nonNullNameList.stream()
                        .collect(Collectors.groupingBy(InvoicedReceiptDTO::getInvoiceNumber))
                        .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)+"条");
                    });
                }
            }
            //判断本次数电发票号码是否重复
            List<InvoicedReceiptDTO> nonNullElectronNameList = invoicedReceiptData.stream()
                    .filter(p -> StringUtils.isNotEmpty(p.getElectronInvoiceNumber()))
                    .toList();
            if(CollectionUtils.isNotEmpty(nonNullElectronNameList)){
                Map<String, List<InvoicedReceiptDTO>> electronExt = nonNullElectronNameList.stream()
                        .collect(Collectors.groupingBy(InvoicedReceiptDTO::getElectronInvoiceNumber))
                        .entrySet().stream()
                        .filter(entry -> entry.getValue().size() > 1)
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
                if (ObjectUtil.isNotNull(electronExt)){
                    electronExt.forEach((key, value) -> {
                        throw new DaoException("数电发票号码："+key+"重复录入"+value.size()+"条，请删除其中"+(value.size()-1)+"条");
                    });
                }
            }
            //判断发票号码是否重复
            for (InvoicedReceiptDTO invoicedReceipt : invoicedReceiptData){
                if(StrUtil.isNotEmpty(invoicedReceipt.getInvoiceNumber())){
                    InvoicedReceipt invoicedReceipt1 = invoicedReceiptService.getExitDataByIaIdAndInvoiceNumber(iaId,invoicedReceipt.getInvoiceNumber());
                    if (ObjectUtil.isNotNull(invoicedReceipt1)){
                        throw new DaoException("发票号码："+invoicedReceipt.getInvoiceNumber()+"在系统中已存在，不可录入");
                    }
                }

            }
            //判断数电发票号码是否重复
            for (InvoicedReceiptDTO invoicedReceipt : invoicedReceiptData){
                invoicedReceipt.setDeleteFlag(0);
                if(StrUtil.isNotEmpty(invoicedReceipt.getElectronInvoiceNumber())){
                    invoicedReceipt.setElectronInvoiceNumber(invoicedReceipt.getElectronInvoiceNumber().trim());//去除空格
                    InvoicedReceipt invoicedReceipt1 = invoicedReceiptService.getExitDataByIaIdAndElectronInvoiceNumber(iaId,invoicedReceipt.getElectronInvoiceNumber());
                    if (ObjectUtil.isNotNull(invoicedReceipt1)){
                        throw new DaoException("数电发票号码："+invoicedReceipt.getElectronInvoiceNumber()+"在系统中已存在，不可录入");
                    }
                }
            }
            // 新增或编辑
            invoicedReceiptService.saveOrUpdateBatch(invoicedReceiptConvert.dto2EntityList(invoicedReceiptData));

        }
    }

    @Override
    public PageView getInvoiceReceiptListByQuery(InvoicedDetailQuery query) {
        final Page<AccountStatement> dbPage = PageUtil.toPage(query);
        List<InvoicedReceiptPO> invoicedReceiptPOS = invoicedReceiptService.findPageByQuery(dbPage, query);
        List<InvoicedReceiptDTO> invoicedReceiptDTOS = invoicedReceiptConvert.po2PageListDTO(invoicedReceiptPOS);
        return PageUtil.getPV(invoicedReceiptDTOS, dbPage.getTotal());
    }

    @Override
    public List<InvoicedReceiptDTO> listAll(InvoicedDetailQuery query) {
        List<InvoicedReceiptPO> invoicedReceiptPOS = invoicedReceiptService.findPageByQuery(null, query);
        return invoicedReceiptConvert.po2PageListDTO(invoicedReceiptPOS);
    }

    @Override
    public void updateDeductionStatus(List<String> idList, String deductionStatus, String note) {
        List<InvoicedReceipt> invoicedReceiptList = invoicedReceiptService.listByIds(idList);
        if (CollectionUtils.isNotEmpty(invoicedReceiptList)){
            for (InvoicedReceipt invoicedReceipt : invoicedReceiptList){
                invoicedReceipt.setNote(note);
                invoicedReceipt.setDeductionStatus(deductionStatus);
            }
        }
        invoicedReceiptService.updateBatchById(invoicedReceiptList);
    }

    @Override
    public List<InvoicedReceiptImportDTO> importData(MultipartFile file) {
        List<InvoicedReceiptImportDTO> cachedDataList = ListUtils.newArrayList();
        //币种
        List<DictDTO> currencys = dictClient.getDicByType(DictCode.CURRENCY.getCode());
        final Map<String, DictDTO> currencyCache = currencys.stream().collect(Collectors.toMap(DictDTO::getCode, a -> a));
        final Set<String> currencyCodes = currencyCache.keySet();
        try {
            EasyExcel.read(file.getInputStream(), InvoicedReceiptImportDTO.class,
                    new ReadListener<InvoicedReceiptImportDTO>() {
                        @Override
                        public void invoke(InvoicedReceiptImportDTO data, AnalysisContext context) {
                            final String currencyCode = data.getCurrencyCode();
                            final String deductionCodeTypeStr = data.getDeductionCodeTypeStr();
                            if (StringUtils.isNotEmpty(deductionCodeTypeStr)&&"可抵扣".equals(deductionCodeTypeStr)){
                                data.setDeductionCodeType(1);
                            }
                            if (StringUtils.isNotEmpty(deductionCodeTypeStr)&&"不可抵扣".equals(deductionCodeTypeStr)){
                                data.setDeductionCodeType(2);
                            }
                            if (StringUtils.isNotEmpty(currencyCode)&&!currencyCodes.contains(currencyCode)){
                                throw new DaoException(StrUtil.format("币种：{}在系统中不存在",currencyCode));
                            }
                            cachedDataList.add(data);
                        }
                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        }
                    }).sheet().doRead();
        } catch (IOException e) {
            throw new DaoException("导入失败！");
        }
        return cachedDataList;
    }
}
