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

import java.io.File;
import java.time.LocalDate;
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 org.springframework.util.StringUtils;

import com.ecep.contract.IEntityService;
import com.ecep.contract.QueryService;
import com.ecep.contract.ds.company.CompanyFileUtils;
import com.ecep.contract.ds.company.repository.CompanyOldNameRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyOldName;
import com.ecep.contract.util.MyStringUtils;
import com.ecep.contract.util.SpecificationUtils;
import com.fasterxml.jackson.databind.JsonNode;

@Lazy
@Service
public class CompanyOldNameService implements IEntityService<CompanyOldName>, QueryService<CompanyOldName> {
    private static final Logger logger = LoggerFactory.getLogger(CompanyOldNameService.class);
    @Lazy
    @Autowired
    private CompanyOldNameRepository companyOldNameRepository;
    @Lazy
    @Autowired
    private CompanyService companyService;

    public CompanyOldName findById(Integer id) {
        return companyOldNameRepository.findById(id).orElse(null);
    }

    @Override
    public Specification<CompanyOldName> getSpecification(String searchText) {
        if (!StringUtils.hasText(searchText)) {
            return null;
        }
        return SpecificationUtils.andWith(searchText, this::buildSearchSpecification);
    }

    protected Specification<CompanyOldName> buildSearchSpecification(String searchText) {
        return (root, query, builder) -> {
            return builder.or(
                    builder.like(root.get("name"), "%" + searchText + "%"),
                    builder.like(root.get("memo"), "%" + searchText + "%"));
        };
    }

    public CompanyOldName save(CompanyOldName companyOldName) {
        return companyOldNameRepository.save(companyOldName);
    }

    public boolean makePathAbsent(CompanyOldName companyOldName) {
        String path = companyOldName.getPath();
        if (StringUtils.hasText(path)) {
            File file = new File(path);
            if (file.exists()) {
                return false;
            }
        }

        File dir = makePath(companyOldName);
        if (dir == null) {
            return false;
        }
        if (!dir.exists()) {
            return false;
        }
        companyOldName.setPath(dir.getAbsolutePath());
        return true;
    }

    public File makePath(CompanyOldName companyOldName) {
        String oldName = companyOldName.getName();
        File basePath = companyService.getBasePath();
        Company company = companyService.findById(companyOldName.getCompanyId());
        String district = company.getDistrict();
        if (StringUtils.hasText(district)) {
            String parentPrefix = CompanyFileUtils.getParentPrefixByDistrict(district);
            if (parentPrefix != null) {
                File parent = new File(basePath, parentPrefix);
                if (!parent.exists()) {
                    if (!parent.mkdir()) {
                        return null;
                    }
                }
                String fileName = CompanyFileUtils.escapeFileName(oldName);
                File dir = new File(parent, fileName);
                if (!dir.exists()) {
                    if (!dir.mkdir()) {
                        return null;
                    }
                }
                return dir;
            }
        }
        return null;
    }

    public List<CompanyOldName> findAllByName(String name) {
        return companyOldNameRepository.findAllByName(name);
    }

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

    public List<CompanyOldName> findAllByCompany(Company company) {
        return companyOldNameRepository.findAllByCompanyId(company.getId());
    }

    public CompanyOldName findMatchByDate(Company company, LocalDate date) {
        List<CompanyOldName> oldNames = findAllByCompany(company);
        if (oldNames == null || oldNames.isEmpty()) {
            return null;
        }
        return oldNames.stream().filter(v -> {
            if (v.getAmbiguity()) {
                return false;
            }
            if (v.getBeginDate() != null && date.isBefore(v.getBeginDate())) {
                return false;
            }
            if (v.getEndDate() != null && date.isAfter(v.getEndDate())) {
                return false;
            }
            return true;
        }).findFirst().orElse(null);
    }

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

    public void delete(CompanyOldName entity) {
        companyOldNameRepository.delete(entity);
    }

    public List<CompanyOldName> findAllByCompanyAndName(Company company, String oldName) {
        return companyOldNameRepository.findAllByCompanyIdAndName(company.getId(), oldName);
    }

    /**
     * 将 from 的曾用名 关联到 to
     *
     * @param from from
     * @param to   to
     */
    public void resetTo(Company from, Company to) {
        // 曾用名 关联到 to
        List<CompanyOldName> list = companyOldNameRepository.findAllByCompanyId(from.getId());
        if (list.isEmpty()) {
            return;
        }
        for (CompanyOldName oldName : list) {
            oldName.setMemo(MyStringUtils.appendIfAbsent(oldName.getMemo(), "转自 " + from.getId()));
            oldName.setCompanyId(to.getId());
        }
        companyOldNameRepository.saveAll(list);
    }

    public void deleteByCompany(Company company) {
        int deleted = companyOldNameRepository.deleteAllByCompanyId(company.getId());
        if (deleted > 0) {
            if (logger.isInfoEnabled()) {
                logger.info("Delete {} records by company:#{}", deleted, company.getId());
            }
        }
    }

    /**
     * 根据提供的搜索文本查询公司旧名称列表。
     * <p>
     * 该函数使用JPA的Specification接口构建查询条件，查找公司旧名称中包含指定文本的记录。
     * 查询结果最多返回10条记录。
     *
     * @param searchText 用于搜索的文本，将匹配公司旧名称中包含该文本的记录。
     * @return 包含匹配的公司旧名称的列表，列表中的每个元素都是一个CompanyOldName对象。
     */
    public List<CompanyOldName> search(String searchText) {
        return companyOldNameRepository.findAll(getSpecification(searchText), Pageable.ofSize(10)).getContent();
    }

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

    @Override
    public Page<CompanyOldName> findAll(JsonNode paramsNode, Pageable pageable) {
        Specification<CompanyOldName> spec = null;
        if (paramsNode.has("searchText")) {
            spec = getSpecification(paramsNode.get("searchText").asText());
        }
        if (paramsNode.has("company")) {
            JsonNode param = paramsNode.get("company");
            Integer companyId = null;
            if (param.isInt()) {
                companyId = param.asInt();
            } else if (param.isObject()) {
                companyId = param.get("id").asInt();
            }
            if (companyId != null) {
                final int id = companyId;
                spec = SpecificationUtils.and(spec, (root, query, builder) -> {
                    return builder.equal(root.get("companyId"), id);
                });
            }
        }
        return findAll(spec, pageable);
    }

    public CompanyOldName createNew(Company company, String name, boolean ambiguity) {
        CompanyOldName companyOldName = new CompanyOldName();
        companyOldName.setCompanyId(company.getId());
        companyOldName.setName(name);
        companyOldName.setAmbiguity(ambiguity);
        return companyOldName;
    }
}
