package com.ecep.contract.ds.vendor.service;

import java.io.File;
import java.time.LocalDate;
import java.util.Comparator;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.ecep.contract.ContractPayWay;
import com.ecep.contract.IEntityService;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.QueryService;
import com.ecep.contract.SpringApp;
import com.ecep.contract.VendorFileType;
import com.ecep.contract.constant.CompanyVendorConstant;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.company.service.HolidayService;
import com.ecep.contract.ds.contract.model.Contract;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.ds.other.service.SysConfService;
import com.ecep.contract.ds.vendor.model.Vendor;
import com.ecep.contract.ds.vendor.model.VendorFile;
import com.ecep.contract.ds.vendor.repository.VendorFileRepository;
import com.ecep.contract.service.ServiceException;
import com.ecep.contract.service.VoableService;
import com.ecep.contract.util.SpecificationUtils;
import com.ecep.contract.vo.CompanyVo;
import com.ecep.contract.vo.VendorFileVo;
import com.ecep.contract.vo.VendorVo;
import com.fasterxml.jackson.databind.JsonNode;

@Lazy
@Service
public class VendorFileService
        implements IEntityService<VendorFile>, QueryService<VendorFile>, VoableService<VendorFile, VendorFileVo> {

    private static final Logger logger = LoggerFactory.getLogger(VendorFileService.class);

    public File getEvaluationFormTemplate() {
        SysConfService confService = SpringApp.getBean(SysConfService.class);
        String path = confService.getString(CompanyVendorConstant.KEY_EVALUATION_FORM_TEMPLATE);
        if (path == null) {
            return null;
        }
        return new File(path);
    }

    @Autowired
    private VendorFileRepository repository;

    @Override
    public VendorFile getById(Integer id) {
        return repository.findById(id).orElse(null);
    }

    public VendorFile findById(Integer id) {
        return repository.findById(id).orElse(null);
    }

    @Override
    public Specification<VendorFile> getSpecification(String searchText) {
        return (root, query, builder) -> {
            return builder.or(builder.like(root.get("filePath"), "%" + searchText + "%"));
        };
    }

    @Override
    public Page<VendorFile> findAll(Specification<VendorFile> spec, Pageable pageable) {
        return repository.findAll(spec, pageable);
    }

    @Override
    public Page<VendorFile> findAll(JsonNode paramsNode, Pageable pageable) {
        Specification<VendorFile> spec = null;
        if (paramsNode.has("searchText")) {
            spec = getSpecification(paramsNode.get("searchText").asText());
        }
        // 添加额外的参数过滤
        if (paramsNode.has("type")) {
            VendorFileType type = VendorFileType.valueOf(paramsNode.get("type").asText());
            spec = SpecificationUtils.and(spec, (root, query, builder) -> builder.equal(root.get("type"), type));
        }
        spec = SpecificationUtils.andFieldEqualParam(spec, paramsNode, "valid");
        spec = SpecificationUtils.andParam(spec, paramsNode, "vendor");
        return findAll(spec, pageable);
    }

    public List<VendorFile> findAllByVendor(Vendor vendor) {
        return repository.findAllByVendorId(vendor.getId());
    }

    public List<VendorFileVo> findAllByVendor(VendorVo vendor) {
        return repository.findAllByVendorId(vendor.getId()).stream().map(VendorFile::toVo).toList();
    }

    public void delete(VendorFile file) {
        repository.delete(file);
    }

    public void deleteById(int id) {
        repository.deleteById(id);
    }

    public void saveAll(List<VendorFile> files) {
        repository.saveAll(files);
    }

    public VendorFile save(VendorFile file) {
        return repository.save(file);
    }

    public List<VendorFile> findAll(Specification<VendorFile> spec, Sort sort) {
        return repository.findAll(spec, sort);
    }

    public List<VendorFile> findAllByVendorAndType(Vendor vendor, VendorFileType type) {
        return repository.findAllByVendorAndType(vendor, type);
    }

    public List<VendorFile> findAllByVendorAndType(VendorVo vendor, VendorFileType type) {
        return repository.findAllByVendorIdAndType(vendor.getId(), type);
    }

    /**
     * 验证供应商文件
     *
     * @param vendor     供应商
     * @param verifyDate 验证日期
     * @param holder     状态输出
     */
    public void verify(Vendor vendor, LocalDate verifyDate, MessageHolder holder) {
        // 验证最早日期，之前属于历史问题，不做处理
        LocalDate minDate = LocalDate.of(2022, 1, 1);
        if (verifyDate.isBefore(minDate)) {
            return;
        }

        // 查询所有评价表
        List<VendorFile> files = findAllByVendorAndType(vendor, VendorFileType.EvaluationForm);
        if (files == null || files.isEmpty()) {
            holder.error("未见供应商评价");
            return;
        }

        // 检索 验证日期最近一年内的有效评价表，日期宽限7天
        LocalDate begin = verifyDate.plusYears(-1);
        VendorFile vendorFile = files.stream()
                .filter(v -> v.getSignDate() != null && v.isValid())
                .filter(v -> MyDateTimeUtils.dateValidFilter(v.getSignDate(), begin, verifyDate, 7))
                .findFirst().orElse(null);
        if (vendorFile == null) {
            // 检索最后一个有效评价表
            VendorFile latestFile = files.stream()
                    .filter(v -> v.getSignDate() != null && v.isValid())
                    .max(Comparator.comparing(VendorFile::getSignDate))
                    .orElse(null);

            if (latestFile == null) {
                holder.error("未匹配的供应商评价");
                return;
            }
            // 提示评价表已过期
            holder.error("供应商评价已过期：" + latestFile.getSignDate() + ", 检测日期：" + verifyDate);
        }
    }

    /**
     * 根据合同 和 评价表情况计算下一个评价日期
     *
     * @param vendor 供应商
     * @return 下一个评价日期
     */
    public LocalDate getNextSignDate(VendorVo vendor, MessageHolder holder) {
        LocalDate miniContractDate = LocalDate.of(2022, 1, 1);

        // 检索全部合同
        ContractService contractService = SpringApp.getBean(ContractService.class);
        CompanyService companyService = SpringApp.getBean(CompanyService.class);
        CompanyVo company = companyService.findById(vendor.getCompanyId());
        List<Contract> contractList = contractService.findAllByCompany(company, ContractPayWay.PAY, miniContractDate,
                LocalDate.now());
        if (contractList.isEmpty()) {
            holder.error("未发现已登记的合同");
            return null;
        }
        // 检索评价表
        List<VendorFile> files = findAllByVendorAndType(vendor, VendorFileType.EvaluationForm);
        VendorFile latestFile = files.stream()
                .filter(v -> v.getSignDate() != null && v.isValid())
                .max(Comparator.comparing(VendorFile::getSignDate))
                .orElse(null);

        // 没有有效的评价表的评价日期
        if (latestFile == null) {
            holder.warn("未发现有效的评价表");
            // 返回最早的合同日期
            Contract firstContract = contractList.stream()
                    .filter(v -> v.getSetupDate() != null && !v.getSetupDate().isBefore(miniContractDate))
                    .min(Comparator.comparing(Contract::getSetupDate))
                    .orElse(null);
            if (firstContract == null) {
                holder.error("最早的合同不存在?");
                return null;
            }

            LocalDate setupDate = firstContract.getSetupDate();
            holder.info("依据合同 " + firstContract.getCode() + " 的日期 " + setupDate + " 推算");
            return SpringApp.getBean(HolidayService.class).adjustToWorkDay(setupDate.plusDays(-7));
        }

        // 检查失效日期起的第一个合同
        LocalDate nextInValidDate = latestFile.getSignDate().plusYears(1);
        File file = new File(latestFile.getFilePath());
        holder.info("依据 " + file.getName() + " 的失效期 " + nextInValidDate + " 检索合同");
        List<Contract> matchedContracts = contractList.stream()
                .filter(v -> v.getSetupDate().isAfter(nextInValidDate)).toList();
        // 没有在失效日期后的合同时，使用失效日期
        if (matchedContracts.isEmpty()) {
            holder.warn("未发现失效期 " + nextInValidDate + " 后的合同");
            return null;
        }
        holder.info("发现匹配合同 " + matchedContracts.size() + " 个");

        // 按时间取最早一个
        Contract firstContract = matchedContracts.stream()
                .min(Comparator.comparing(Contract::getSetupDate))
                .orElse(null);
        LocalDate setupDate = firstContract.getSetupDate();
        holder.info("匹配失效期 " + nextInValidDate + " 后的第一个合同 " + firstContract.getCode());
        holder.info("依据合同 " + firstContract.getCode() + " 的日期 " + setupDate + " 推算");
        return SpringApp.getBean(HolidayService.class).adjustToWorkDay(setupDate.plusDays(-7));
    }

    @Override
    public void updateByVo(VendorFile model, VendorFileVo vo) {
        if (model == null) {
            throw new ServiceException("VendorFile cannot be null");
        }
        if (vo == null) {
            throw new ServiceException("VendorFileVo cannot be null");
        }

        // Map properties from VO to entity
        model.setType(vo.getType());
        model.setFilePath(vo.getFilePath());
        model.setEditFilePath(vo.getEditFilePath());
        model.setSignDate(vo.getSignDate());
        model.setValid(vo.isValid());

        // 处理关联实体 - 供应商
        if (vo.getVendorId() == null) {
            model.setVendor(null);
        } else {
            VendorService vendorService = SpringApp.getBean(VendorService.class);
            if (model.getVendor() == null || !model.getVendor().getId().equals(vo.getVendorId())) {
                model.setVendor(vendorService.getById(vo.getVendorId()));
            }
        }

    }
}
