package com.ecep.contract.controller.vendor.approved_list;

import java.io.File;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.util.StringUtils;

import com.ecep.contract.CompanyVendorFileType;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.VendorType;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyOldName;
import com.ecep.contract.model.CompanyVendor;
import com.ecep.contract.model.CompanyVendorApprovedItem;
import com.ecep.contract.model.CompanyVendorApprovedList;
import com.ecep.contract.model.CompanyVendorFile;
import com.ecep.contract.model.Contract;
import com.ecep.contract.service.CompanyOldNameService;
import com.ecep.contract.service.CompanyVendorApprovedItemService;
import com.ecep.contract.service.CompanyVendorApprovedListService;
import com.ecep.contract.service.CompanyVendorFileService;
import com.ecep.contract.service.CompanyVendorService;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.task.Tasker;
import com.ecep.contract.util.ParamUtils;
import com.ecep.contract.util.ProxyUtils;

import lombok.Setter;

/**
 * 从现有的供应商中导入
 */
public class CompanyVendorApprovedListVendorImportTask extends Tasker<Object> {
    private static final Logger logger = LoggerFactory.getLogger(CompanyVendorApprovedListVendorImportTask.class);
    // Meet qualified supplier standards
    public static final String STR_MEET_QUALIFIED = "符合合格供方标准";
    public static final String STR_MEET_TYPICALLY = "符合一般供方标准";
    public static final String STR_MEET_UNQUALIFIED = "符合不合格供方标准";

    private final CompanyVendorApprovedList approvedList;

    private CompanyVendorApprovedListService service;
    private CompanyVendorApprovedItemService itemService;
    private CompanyVendorFileService companyVendorFileService;
    private CompanyOldNameService companyOldNameService;
    private ContractService contractService;

    private final AtomicInteger counter = new AtomicInteger(0);

    public CompanyVendorApprovedListVendorImportTask(CompanyVendorApprovedList approvedList) {
        this.approvedList = approvedList;
        updateTitle("供方名录-供方导入");
    }

    private CompanyVendorApprovedItemService getItemService() {
        if (itemService == null) {
            itemService = getBean(CompanyVendorApprovedItemService.class);
        }
        return itemService;
    }

    private CompanyVendorFileService getCompanyVendorFileService() {
        if (companyVendorFileService == null) {
            companyVendorFileService = getBean(CompanyVendorFileService.class);
        }
        return companyVendorFileService;
    }

    private CompanyOldNameService getCompanyOldNameService() {
        if (companyOldNameService == null) {
            companyOldNameService = getBean(CompanyOldNameService.class);
        }
        return companyOldNameService;
    }

    private ContractService getContractService() {
        if (contractService == null) {
            contractService = getBean(ContractService.class);
        }
        return contractService;
    }

    @Override
    protected Object execute(MessageHolder holder) throws Exception {
        LocalDate endDate = approvedList.getPublishDate();
        if (endDate == null) {
            holder.error("供方名录的发布日期未定义");
            return null;
        }

        service = getBean(CompanyVendorApprovedListService.class);
        CompanyVendorService vendorService = getBean(CompanyVendorService.class);
        Page<CompanyVendor> page = vendorService.findAll(
                ParamUtils.builder()
                        .isNotNull("created")
                        .lessThan("developDate", endDate)
                        .build(),
                Pageable.unpaged());
        holder.debug("读取到" + page.getTotalElements());
        try (Stream<CompanyVendor> stream = page.stream()) {
            stream.forEach(v -> {
                if (isCancelled()) {
                    holder.debug("Cancelled");
                    return;
                }

                MessageHolder sub = holder.sub(counter.get() + "/" + page.getTotalElements() + "> ");

                sync(v, sub);
                updateProgress(counter.incrementAndGet(), page.getTotalElements());
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 是否输出不合格供应商
     */
    @Setter
    private boolean logUnqualifiedVendor = true;
    /**
     * 是否输出近3年没有合同信息
     */
    @Setter
    private boolean logTypicallyVendorNoThreeYearContract = true;

    private void sync(CompanyVendor vendor, MessageHolder holder) {
        // 明确 company 实例
        Company company = initializedVendorCompany(vendor);
        if (company == null) {
            // 无效
            return;
        }

        MessageHolder subHolder = holder.sub(company.getName() + " ");

        VendorType vendorType = vendor.getType();
        if (vendorType == null) {
            subHolder.error("供方的分类为空");
            return;
        }

        // 确认供方的developDate 是否在供方名录的发布日期之后
        LocalDate developDate = vendor.getDevelopDate();
        if (developDate == null) {
            subHolder.error("供方的开发日期为空");
        } else if (developDate.isAfter(approvedList.getPublishDate())) {
            return;
        }

        // 确认供方是否在供方名录中,可能有多个，所以返回 list，默认取第一个
        List<CompanyVendorApprovedItem> items = getItemService().findAllByListAndVendor(approvedList, vendor);
        if (items == null || items.isEmpty()) {
            // 供方不在供方名录中时，新建一个
            CompanyVendorApprovedItem item = new CompanyVendorApprovedItem();
            item.setList(approvedList);
            item.setVendor(vendor);

            // 当前供应商分类是不合格供应商时
            if (vendorType == VendorType.UNQUALIFIED) {
                // 检索查看供方的评价表, 看与发布日期期间是否有评价表
                if (!checkAsQualifiedVendorByEvaluationFormFiles(vendor, item, subHolder)) {
                    // 不合同供方，跳过
                    if (logUnqualifiedVendor) {
                        subHolder.info("供方是不合格供方, 不纳入名录");
                    }
                    // 上一年度的供方目录中是否有此供应商
                    return;
                }
                item.setDescription("");
            }
            // 当前供应商分类是合格供方时
            else if (vendorType == VendorType.TYPICALLY) {
                // 协议经销商，认定为合格供方
                if (vendor.isProtocolProvider()) {
                    item.setType(VendorType.QUALIFIED);
                    item.setDescription("协议经销商");
                }
                // 非协议经销商
                else {
                    // 查看供方的合同，看近3年期间是否有合同
                    List<Contract> contracts = findAllVendorContracts(vendor, approvedList.getPublishDate());
                    if (contracts.isEmpty()) {
                        // 没有合同，应该归入不合格供应商
                        // 保持一般供应商分类，后期流程处理是否变更分类
                        item.setType(VendorType.TYPICALLY);
                        if (logTypicallyVendorNoThreeYearContract) {
                            subHolder.warn("供方近" + vendorContractMinusYear + "年没有合作, 应该转为不合格供应商");
                        }
                        item.setDescription(STR_MEET_UNQUALIFIED);
                    } else {
                        // 检查近3年期间是否都有合同
                        if (checkAllYearHasContract(contracts, approvedList.getPublishDate())) {
                            // 每年都有合同，合同数是否符合合格供方标准
                            if (checkAllYearMinHasContract(contracts, approvedList.getPublishDate())) {
                                // 保持一般供应商分类，后期流程处理是否变更分类
                                item.setType(VendorType.TYPICALLY);
                                subHolder.info("供方近" + vendorContractMinusYear + "年每年都有合作, 符合合格供方标准");
                                item.setDescription(STR_MEET_QUALIFIED);
                            } else {
                                item.setType(VendorType.TYPICALLY);
                                subHolder.warn("供方近" + vendorContractMinusYear + "年每年都有合作, 但是合同数不足, 应转为一般供应商");
                                item.setDescription(STR_MEET_TYPICALLY);
                            }
                        } else {
                            item.setType(VendorType.TYPICALLY);
                            item.setDescription("");
                        }
                    }
                }
            }
            // 当前供应商分类是合格供方时
            else if (vendorType == VendorType.QUALIFIED) {
                // 查看供方的合同，看近3年期间是否有合同
                List<Contract> contracts = findAllVendorContracts(vendor, approvedList.getPublishDate());
                item.setType(vendorType);
                if (contracts.isEmpty()) {
                    if (logTypicallyVendorNoThreeYearContract) {
                        subHolder.warn("供方近" + vendorContractMinusYear + "年没有合作, 应该转为不合格供应商");
                    }
                    item.setDescription(STR_MEET_UNQUALIFIED);
                } else {
                    // 检查近3年期间是否都有合同
                    if (checkAllYearHasContract(contracts, approvedList.getPublishDate())) {
                        // 每年都有合同，合同数是否符合合格供方标准
                        if (checkAllYearMinHasContract(contracts, approvedList.getPublishDate())) {
                            item.setDescription("");
                        } else {
                            subHolder.warn("供方近" + vendorContractMinusYear + "年每年都有合作, 但是合同数不足, 应转为一般供应商");
                            item.setDescription(STR_MEET_TYPICALLY);
                        }
                    } else {
                        subHolder.warn("供方近" + vendorContractMinusYear + "年非每年都有合作");
                        item.setDescription("");
                    }
                }
            }
            // 未知分类时
            else {
                item.setDescription("未知供方分类");
            }

            // 匹配的历史名称
            updateVendorNameWithOldName(vendor, item);
            getItemService().save(item);
            return;
        }

        if (items.size() == 1) {
            CompanyVendorApprovedItem first = items.getFirst();
            if (!StringUtils.hasText(first.getVendorName())) {
                updateVendorNameWithOldName(vendor, first);
            }
            updateItem(vendor, first, subHolder);
            return;
        }

        for (int i = 1; i < items.size(); i++) {
            CompanyVendorApprovedItem item = items.get(i);
            getItemService().delete(item);
            subHolder.debug("删除重复的供方名录项：#" + item.getId());
        }
    }

    private void updateVendorNameWithOldName(CompanyVendor vendor, CompanyVendorApprovedItem item) {
        Company company = initializedVendorCompany(vendor);
        if (company == null) {
            return;
        }
        CompanyOldName companyOldName = getCompanyOldNameService().findMatchByDate(company,
                approvedList.getPublishDate());
        if (companyOldName != null) {
            item.setVendorName(companyOldName.getName());
        }
    }

    /**
     *
     */
    @Setter
    private boolean logUnqualifiedVendorRemove = true;

    private void updateItem(
            CompanyVendor vendor, CompanyVendorApprovedItem item, MessageHolder holder) {
        VendorType t1 = item.getType();
        VendorType vendorType = vendor.getType();
        CompanyVendorApprovedItemService itemService = getItemService();
        if (t1 != vendorType) {
            holder.warn("注意分类不一致, " + t1 + ", " + vendorType + ".");
        }
        if (t1 == VendorType.UNQUALIFIED) {
            // 查看供方的评价表, 看与发布日期期间是否有评价表
            if (checkAsQualifiedVendorByEvaluationFormFiles(vendor, item, holder)) {

                itemService.save(item);
            } else {
                // 不合格供方，移除
                if (logUnqualifiedVendorRemove) {
                    holder.error("供方是不合格供方");
                }
            }
        } else if (t1 == VendorType.TYPICALLY) {
            // 协议经销商，认定为合格供方
            if (vendor.isProtocolProvider()) {
                // 协议经销商，认定为合格供方
                item.setType(VendorType.QUALIFIED);
                item.setDescription("协议经销商, 应该转为合格供应商");
                itemService.save(item);
            }
            // 非协议经销商
            else {
                // 查看供方的合同，看近3年期间是否有合同
                List<Contract> contracts = findAllVendorContracts(vendor, approvedList.getPublishDate());
                if (contracts.isEmpty()) {
                    // 没有合同，应该归入不合格供应商
                    if (logTypicallyVendorNoThreeYearContract) {
                        holder.warn("供方近" + vendorContractMinusYear + "年没有合作, 应该转为不合格供应商");
                    }

                    if (!Objects.equals(item.getDescription(), STR_MEET_UNQUALIFIED)) {
                        item.setDescription(STR_MEET_UNQUALIFIED);
                        itemService.save(item);
                    }
                } else {
                    // 检查近3年期间是否都有合同
                    if (checkAllYearHasContract(contracts, approvedList.getPublishDate())) {
                        // 每年都有合同，合同数是否符合合格供方标准
                        if (checkAllYearMinHasContract(contracts, approvedList.getPublishDate())) {
                            holder.info("供方近" + vendorContractMinusYear + "年每年都有合作, 符合合格供方标准");
                            if (!Objects.equals(item.getDescription(), STR_MEET_QUALIFIED)) {
                                item.setDescription(STR_MEET_QUALIFIED);
                                itemService.save(item);
                            }
                        } else {
                            holder.warn("供方近" + vendorContractMinusYear + "年每年都有合作, 但是合同数不足, 应转为一般供应商");
                            if (!Objects.equals(item.getDescription(), "")) {
                                item.setDescription(STR_MEET_TYPICALLY);
                                itemService.save(item);
                            }
                        }
                    } else {
                        if (!Objects.equals(item.getDescription(), "")) {
                            item.setDescription("");
                            itemService.save(item);
                        }
                    }
                }
            }
        }
        // 当前供应商分类是合格供方时
        else if (t1 == VendorType.QUALIFIED) {
            // 协议经销商，认定为合格供方
            if (vendor.isProtocolProvider()) {
                // 协议经销商，认定为合格供方
                if (!Objects.equals(item.getDescription(), "协议经销商")) {
                    item.setDescription("协议经销商");
                    itemService.save(item);
                }
                return;
            }
            // 查看供方的合同，看近3年期间是否有合同
            List<Contract> contracts = findAllVendorContracts(vendor, approvedList.getPublishDate());
            if (contracts.isEmpty()) {
                if (logTypicallyVendorNoThreeYearContract) {
                    holder.warn("供方近" + vendorContractMinusYear + "年没有合作, 应该转为不合格供应商");
                }
                if (!Objects.equals(item.getDescription(), STR_MEET_UNQUALIFIED)) {
                    item.setDescription(STR_MEET_UNQUALIFIED);
                    itemService.save(item);
                }
                return;
            }

            // 检查近3年期间是否都有合同
            if (checkAllYearHasContract(contracts, approvedList.getPublishDate())) {
                // 每年都有合同，合同数是否符合合格供方标准
                if (checkAllYearMinHasContract(contracts, approvedList.getPublishDate())) {
                    if (!Objects.equals(item.getDescription(), "")) {
                        item.setDescription("");
                        itemService.save(item);
                    }
                } else {
                    holder.warn("供方近" + vendorContractMinusYear + "年每年都有合作, 但是合同数不足, 应转为一般供应商");
                    if (!Objects.equals(item.getDescription(), STR_MEET_TYPICALLY)) {
                        item.setDescription(STR_MEET_TYPICALLY);
                        itemService.save(item);
                    }
                }
            } else {
                holder.info("供方近" + vendorContractMinusYear + "年非每年都有合作");
            }
        }
    }

    /**
     * 根据评价表，判断是否转为一般供方
     *
     * @param vendor 供应商对象
     * @param item   供方名录中供应商的条目
     * @param holder 消息输出器
     * @return true if qualified
     * @see #findAllEvaluationFormFiles(CompanyVendor, LocalDate)
     */
    private boolean checkAsQualifiedVendorByEvaluationFormFiles(
            CompanyVendor vendor, CompanyVendorApprovedItem item, MessageHolder holder) {
        List<CompanyVendorFile> files = findAllEvaluationFormFiles(vendor, approvedList.getPublishDate());
        if (files.isEmpty()) {
            return false;
        }

        CompanyVendorFile first = files.getFirst();
        item.setType(VendorType.TYPICALLY);
        File file = new File(first.getFilePath());
        holder.info("供方是不合格供方, 但在发布期一年内有有效评价表 " + file.getName() + ", 调整为一般供应商");
        item.setDescription(STR_MEET_TYPICALLY);
        return true;
    }

    /**
     * 不满足3年都有合同的条件，输出3年的合同情况
     * The condition of a three-year contract is not met
     * 如果为 true，则在供应商不符合合格供方标准时，记录其近3年的合作情况。
     */
    @Setter
    private boolean logTypicallyVendorNoThreeYearContractDetail = true;

    /**
     * 合格供应商，每年的最少合同数量
     */
    @Setter
    private int everyYearMinContracts = 2;

    /**
     * 检查近3年期间是否都有合同
     *
     * @param list 合同列表
     * @param date 日期
     * @return 3年内是否都有合同
     */
    private boolean checkAllYearHasContract(List<Contract> list, LocalDate date) {
        int end = date.getYear();
        boolean[] has = new boolean[vendorContractMinusYear];
        for (Contract contract : list) {
            LocalDate setupDate = contract.getSetupDate();
            if (setupDate != null) {
                has[end - setupDate.getYear()] = true;
            }
        }
        for (boolean b : has) {
            if (!b) {
                return false;
            }
        }
        return true;
    }

    private boolean checkAllYearMinHasContract(List<Contract> list, LocalDate date) {
        int end = date.getYear();
        int[] has = new int[vendorContractMinusYear];
        for (Contract contract : list) {
            LocalDate setupDate = contract.getSetupDate();
            if (setupDate != null) {
                has[end - setupDate.getYear()]++;
            }
        }
        for (int v : has) {
            if (v < everyYearMinContracts) {
                return false;
            }
        }
        return true;
    }

    private boolean checkAsTypicallyVendorByContracts(
            CompanyVendor vendor, CompanyVendorApprovedItem item, Consumer<String> consumer) {
        // 查看供方的合同，看近3年期间是否有合同
        List<Contract> contracts = findAllVendorContracts(vendor, approvedList.getPublishDate());
        if (contracts.isEmpty()) {
            return false;
        }

        // 合同按年份分组
        Map<Integer, List<Contract>> collect = contracts.stream()
                .collect(Collectors.groupingBy(v -> v.getSetupDate().getYear()));
        // 3年都有合同, 看是否符合合格供方标准
        if (collect.size() == vendorContractMinusYear) {
            // 每年的合同都超过1个合同
            boolean more = true;
            for (List<Contract> value : collect.values()) {
                if (value.size() < everyYearMinContracts) {
                    more = false;
                }
            }
            // 符合合格供方标准
            if (more) {
                consumer.accept("供方近" + vendorContractMinusYear + "年每年都有合作, 符合合格供方标准");

                item.setDescription(STR_MEET_QUALIFIED);
            }
        } else {
            if (logTypicallyVendorNoThreeYearContractDetail) {
                Map<Integer, Integer> m = collect.entrySet().stream()
                        .collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().size()));
                consumer.accept("供方近" + vendorContractMinusYear + "年合作情况" + m + ", 不符合合格供方标准");
            }
        }
        item.setType(VendorType.TYPICALLY);

        return true;
    }

    /**
     * 供应商合同的有效期减去年份数，用于计算合同的有效期截止日期。
     * 默认值为2，表示合同有效期截止日期为当前日期减去2年。
     */
    @Setter
    private int vendorContractMinusYear = 3;

    /**
     * 查询 3年内是否有合同
     * <p>
     * 当 date 参数是 2024-12-12，vendorContractMinusYear 是 3 时，
     * 查询 2022-01-01 到 2024-12-12 之间的合同
     *
     * @param vendor 供应商对象
     * @param date   日期
     * @return 3年内的合同列表
     */
    private List<Contract> findAllVendorContracts(CompanyVendor vendor, LocalDate date) {
        ContractService contractService = getContractService();

        int beginYear = date.getYear() - (vendorContractMinusYear - 1);
        LocalDate miniDate = LocalDate.of(beginYear, 1, 1);

        return contractService.findAllByCompanyVendor(vendor, miniDate, date);
    }

    private Company initializedVendorCompany(CompanyVendor vendor) {
        Company company = vendor.getCompany();
        if (company == null) {
            return null;
        }
        if (!ProxyUtils.isInitialized(company)) {
            company = getCompanyService().findById(company.getId());
            vendor.setCompany(company);
        }
        return company;
    }

    @Setter
    private int vendorFileMinusYear = 1;

    /**
     * 查询
     *
     * @param vendor
     * @param publishDate
     * @return
     */
    private List<CompanyVendorFile> findAllEvaluationFormFiles(CompanyVendor vendor, LocalDate publishDate) {
        CompanyVendorFileService fileService = getCompanyVendorFileService();
        LocalDate miniDate = publishDate.minusYears(vendorFileMinusYear);
        return fileService.findAll(ParamUtils.builder().equals("vendor", vendor.getId()).equals("valid", true)
                .equals("type", CompanyVendorFileType.EvaluationForm).between("signDate", miniDate, publishDate)
                .build(), Pageable.unpaged()).getContent();
    }
}
