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.jwipc.constant.DictCode;
import com.jwipc.exception.DaoException;
import com.jwipc.finance.convert.CostInvoicedReceiptConvert;
import com.jwipc.finance.dto.CostInvoicedReceiptDTO;
import com.jwipc.finance.dto.CostInvoicedReceiptImportDTO;
import com.jwipc.finance.entity.AccountStatement;
import com.jwipc.finance.entity.CostInvoicedReceipt;
import com.jwipc.finance.logic.CostInvoicedReceiptLogic;
import com.jwipc.finance.logic.CostInvoicedReceiptLogic;
import com.jwipc.finance.model.po.CostInvoicedReceiptPO;
import com.jwipc.finance.model.query.InvoicedDetailQuery;
import com.jwipc.finance.service.ICostInvoicedReceiptService;
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 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.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author shenyang.ou
 * @date 2024/3/5 13:27
 * @desc
 */
@Service
@RequiredArgsConstructor
public class CostInvoicedReceiptLogicImpl implements CostInvoicedReceiptLogic {
    private final CostInvoicedReceiptConvert costInvoicedReceiptConvert;
    private final ICostInvoicedReceiptService costInvoicedReceiptService;
    private final DictClient dictClient;

    /**
     * 根据开票申请单ID获取关联发票数据
     *
     * @param iaId 开票申请单ID
     * @return 关联发票数据
     */
    @Override
    public List<CostInvoicedReceiptDTO> getInvoiceReceiptListByIaId(Long iaId) {
        List<CostInvoicedReceiptPO> costInvoicedReceiptPOS = costInvoicedReceiptService.getInvoiceReceiptListByIaId(iaId);;
        return costInvoicedReceiptConvert.po2DTOList(costInvoicedReceiptPOS);
    }

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

            // 删除
            if (CollUtil.isNotEmpty(removeIds)) {
                costInvoicedReceiptService.removeBatchByIds(removeIds);
            }
            //判断本次发票号码是否重复
            List<CostInvoicedReceiptDTO> nonNullNameList = costInvoicedReceiptData.stream()
                    .filter(p -> StringUtils.isNotEmpty(p.getInvoiceNumber()))
                    .toList();
            if(CollectionUtils.isNotEmpty(nonNullNameList)){
                Map<String, List<CostInvoicedReceiptDTO>> ext = nonNullNameList.stream()
                        .collect(Collectors.groupingBy(CostInvoicedReceiptDTO::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<CostInvoicedReceiptDTO> nonNullElectronNameList = costInvoicedReceiptData.stream()
                    .filter(p -> StringUtils.isNotEmpty(p.getElectronInvoiceNumber()))
                    .toList();
            if(CollectionUtils.isNotEmpty(nonNullElectronNameList)){
                Map<String, List<CostInvoicedReceiptDTO>> electronExt = nonNullElectronNameList.stream()
                        .collect(Collectors.groupingBy(CostInvoicedReceiptDTO::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 (CostInvoicedReceiptDTO costInvoicedReceipt : costInvoicedReceiptData){
                if(StrUtil.isNotEmpty(costInvoicedReceipt.getInvoiceNumber())){
                    CostInvoicedReceipt costInvoicedReceipt1 = costInvoicedReceiptService.getExitDataByIaIdAndInvoiceNumber(iaId,costInvoicedReceipt.getInvoiceNumber());
                    if (ObjectUtil.isNotNull(costInvoicedReceipt1)){
                        throw new DaoException("发票号码："+costInvoicedReceipt.getInvoiceNumber()+"在系统中已存在，不可录入");
                    }
                }

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

        }
    }

    @Override
    public PageView getInvoiceReceiptListByQuery(InvoicedDetailQuery query) {
        final Page<AccountStatement> dbPage = PageUtil.toPage(query);
        List<CostInvoicedReceiptPO> costInvoicedReceiptPOS = costInvoicedReceiptService.findPageByQuery(dbPage, query);
        List<CostInvoicedReceiptDTO> costInvoicedReceiptDTOS = costInvoicedReceiptConvert.po2PageListDTO(costInvoicedReceiptPOS);
        return PageUtil.getPV(costInvoicedReceiptDTOS, dbPage.getTotal());
    }

    @Override
    public List<CostInvoicedReceiptDTO> listAll(InvoicedDetailQuery query) {
        List<CostInvoicedReceiptPO> costInvoicedReceiptPOS = costInvoicedReceiptService.findPageByQuery(null, query);
        return costInvoicedReceiptConvert.po2PageListDTO(costInvoicedReceiptPOS);
    }

    @Override
    public void updateDeductionStatus(List<String> idList, String deductionStatus, String note) {
        List<CostInvoicedReceipt> costInvoicedReceiptList = costInvoicedReceiptService.listByIds(idList);
        if (CollectionUtils.isNotEmpty(costInvoicedReceiptList)){
            for (CostInvoicedReceipt costInvoicedReceipt : costInvoicedReceiptList){
                costInvoicedReceipt.setNote(note);
                costInvoicedReceipt.setDeductionStatus(deductionStatus);
            }
        }
        costInvoicedReceiptService.updateBatchById(costInvoicedReceiptList);
    }

    @Override
    public List<CostInvoicedReceiptImportDTO> importData(MultipartFile file) {
        List<CostInvoicedReceiptImportDTO> 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(), CostInvoicedReceiptImportDTO.class,
                    new ReadListener<CostInvoicedReceiptImportDTO>() {
                        @Override
                        public void invoke(CostInvoicedReceiptImportDTO 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;
    }
}
