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

import java.io.File;
import java.time.LocalDate;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
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.CompanyCustomerFileType;
import com.ecep.contract.IEntityService;
import com.ecep.contract.SpringApp;
import com.ecep.contract.constant.CompanyCustomerConstant;
import com.ecep.contract.ds.company.service.CompanyBasicService;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.ds.customer.repository.CompanyCustomerEvaluationFormFileRepository;
import com.ecep.contract.ds.customer.repository.CompanyCustomerFileRepository;
import com.ecep.contract.ds.other.service.SysConfService;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
import com.ecep.contract.model.CompanyCustomerFile;
import com.ecep.contract.model.Contract;

import jakarta.persistence.criteria.Path;

@Lazy
@Service
@CacheConfig(cacheNames = "company-customer-file")
public class CompanyCustomerFileService implements IEntityService<CompanyCustomerFile> {
    private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerFileService.class);
    @Lazy
    @Autowired
    private SysConfService confService;
    @Lazy
    @Autowired
    private CompanyCustomerFileRepository companyCustomerFileRepository;
    @Lazy
    @Autowired
    private CompanyCustomerEvaluationFormFileRepository companyCustomerEvaluationFormFileRepository;

    @Cacheable(key = "#p0")
    public CompanyCustomerFile findById(Integer id) {
        return companyCustomerFileRepository.findById(id).orElse(null);
    }

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

    @Caching(
            evict = {
                    @CacheEvict(key = "#p0.id"),
            }
    )
    public void delete(CompanyCustomerFile file) {
        if (file.getType() == CompanyCustomerFileType.EvaluationForm) {
            companyCustomerEvaluationFormFileRepository.deleteById(file.getId());
        }
        companyCustomerFileRepository.delete(file);
    }

    @Caching(
            evict = {
                    @CacheEvict(key = "#p0.id"),
            }
    )
    public CompanyCustomerFile save(CompanyCustomerFile dbFile) {
        return companyCustomerFileRepository.save(dbFile);
    }

    public CompanyCustomerEvaluationFormFile save(CompanyCustomerEvaluationFormFile formFile) {
        return companyCustomerEvaluationFormFileRepository.save(formFile);
    }

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

    public List<CompanyCustomerFile> findAllByCustomer(CompanyCustomer customer) {
        return companyCustomerFileRepository.findAllByCustomer(customer);
    }

    public void deleteById(int id) {
        Optional<CompanyCustomerFile> optional = companyCustomerFileRepository.findById(id);
        if (optional.isEmpty()) {
            return;
        }
        CompanyCustomerFile customerFile = optional.get();
        if (customerFile.getType() == CompanyCustomerFileType.EvaluationForm) {
            companyCustomerEvaluationFormFileRepository.deleteById(id);
        }
        companyCustomerFileRepository.delete(customerFile);
    }


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


    public List<CompanyCustomerFile> saveAll(List<CompanyCustomerFile> files) {
        return companyCustomerFileRepository.saveAll(files);
    }

    public List<CompanyCustomerFile> findAllByCustomerAndType(CompanyCustomer customer, CompanyCustomerFileType type) {
        return companyCustomerFileRepository.findAllByCustomerAndType(customer, type);
    }

    public List<CompanyCustomerEvaluationFormFile> findAllCustomerEvaluationFormFiles(CompanyCustomer companyCustomer) {
        return findAllByCustomerAndType(companyCustomer, CompanyCustomerFileType.EvaluationForm).stream().map(v -> {
            return companyCustomerEvaluationFormFileRepository.findById(v.getId()).orElseGet(() -> {
                CompanyCustomerEvaluationFormFile formFile = new CompanyCustomerEvaluationFormFile();
                formFile.setCustomerFile(v);
                formFile.setId(v.getId());
                return companyCustomerEvaluationFormFileRepository.save(formFile);
            });
        }).toList();
    }

    public CompanyCustomerEvaluationFormFile findCustomerEvaluationFormFileById(int id) {
        return companyCustomerEvaluationFormFileRepository.findById(id).orElse(null);
    }

    public CompanyCustomerEvaluationFormFile findCustomerEvaluationFormFileByCustomerFile(CompanyCustomerFile customerFile) {
        Integer id = customerFile.getId();
        if (id == null) {
            CompanyCustomerFile saved = companyCustomerFileRepository.save(customerFile);
            id = saved.getId();
            customerFile.setId(id);
        }

        CompanyCustomerEvaluationFormFile formFile = companyCustomerEvaluationFormFileRepository.findById(id).orElse(null);
        if (formFile == null) {
            formFile = new CompanyCustomerEvaluationFormFile();
            formFile.setId(id);
            formFile.setCustomerFile(customerFile);
            companyCustomerEvaluationFormFileRepository.save(formFile);
        }
        return formFile;
    }

    public LocalDate getNextSignDate(CompanyCustomer companyCustomer, Consumer<String> state) {
        LocalDate miniContractDate = LocalDate.of(2022, 1, 1);
        // 检索全部合同
        ContractService contractService = SpringApp.getBean(ContractService.class);
        List<Contract> contractList = contractService.findAllByCompanyCustomer(companyCustomer, null, null);
        if (contractList.isEmpty()) {
            state.accept("未发现已登记的合同");
            return null;
        }
        // 检索评估表
        List<CompanyCustomerFile> files = findAllByCustomerAndType(companyCustomer, CompanyCustomerFileType.EvaluationForm);
        CompanyCustomerFile latestFile = files.stream()
                .filter(v -> v.getSignDate() != null && v.isValid())
                .max(Comparator.comparing(CompanyCustomerFile::getSignDate))
                .orElse(null);

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

            LocalDate setupDate = firstContract.getSetupDate();
            state.accept("依据合同 " + firstContract.getCode() + " 的日期 " + setupDate + " 推算");
            return CompanyBasicService.adjustToWorkDay(setupDate.plusDays(-7));
        }

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

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


    public File getEvaluationFormTemplate() {
        String path = confService.getString(CompanyCustomerConstant.KEY_EVALUATION_FORM_TEMPLATE);
        if (path == null) {
            return null;
        }
        return new File(path);
    }

    /**
     * 将指定源客户的文件记录转移到目标客户下。
     *
     * @param from 源客户对象，其关联的文件将被转移
     * @param to   目标客户对象，将接收源客户的文件记录
     */
    public void resetTo(CompanyCustomer from, CompanyCustomer to) {
        List<CompanyCustomerFile> list = companyCustomerFileRepository.findAllByCustomer(from);
        for (CompanyCustomerFile file : list) {
            file.setCustomer(to);
        }
        companyCustomerFileRepository.saveAll(list);
    }

    public List<CompanyCustomerEvaluationFormFile> searchEvaluationFile(CompanyCustomer customer, String searchText) {
        Specification<CompanyCustomerEvaluationFormFile> spec = (root, query, builder) -> {
            Path<Object> customerFile = root.get("customerFile");
            return builder.and(
                    builder.isNotNull(customerFile),
                    builder.equal(customerFile.get("customer"), customer),
                    builder.equal(customerFile.get("valid"), true),
                    builder.like(customerFile.get("filePath"), "%" + searchText + "%"));
        };
        return companyCustomerEvaluationFormFileRepository.findAll(spec, Pageable.ofSize(10)).getContent();
    }

}
