package com.ecep.contract.service;

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

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.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.ecep.contract.MessageHolder;
import com.ecep.contract.constant.ContractConstant;
import com.ecep.contract.util.ParamUtils;
import com.ecep.contract.vm.ContractViewModel;
import com.ecep.contract.vo.VendorVo;
import com.ecep.contract.vo.ContractFileVo;
import com.ecep.contract.vo.ContractVo;
import com.ecep.contract.vo.ProjectVo;

import io.micrometer.common.util.StringUtils;

@Service
@CacheConfig(cacheNames = "contract")
public class ContractService extends QueryService<ContractVo, ContractViewModel> {
    @Autowired
    private SysConfService confService;

    private File basePath;

    /**
     * 返回合同的基础目录
     *
     * @return 合同的基础目录
     */
    public File getBasePath() {
        if (basePath == null) {
            basePath = new File(confService.getString(ContractConstant.KEY_BASE_PATH));
        }
        return basePath;
    }

    @Cacheable(key = "#p0")
    public ContractVo findById(Integer id) {
        return super.findById(id);
    }

    /**
     * 保存实体对象，异步方法
     */
    @Caching(evict = {
            @CacheEvict(key = "#p0.id"),
            @CacheEvict(key = "'code-'+#p0.code")
    })
    public ContractVo save(ContractVo contract) {
        return super.save(contract);
    }

    @Caching(evict = {
            @CacheEvict(key = "#p0.id"),
            @CacheEvict(key = "'code-'+#p0.code")
    })
    public void delete(ContractVo contract) {
        super.delete(contract);
    }

    public boolean updateParentCode(ContractVo contract) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Unimplemented method 'updateParentCode'");
    }

    @Cacheable(key = "'code-'+#p0")
    public ContractVo findByCode(String code) {
        try {
            return async("findByCode", code, String.class).handle((response, ex) -> {
                if (ex != null) {
                    throw new RuntimeException("远程方法+findByCode+调用失败", ex);
                }
                if (response != null) {
                    return updateValue(createNewEntity(), response);
                }
                return null;
            }).get();
        } catch (Exception e) {
            throw new RuntimeException("查找合同 " + code + " 时发生错误", e);
        }
    }

    public ContractVo findByName(String name) {
        try {
            return async("findByName", name, String.class).handle((response, ex) -> {
                if (response != null) {
                    return updateValue(createNewEntity(), response);
                }
                return null;
            }).get();
        } catch (Exception e) {
            throw new RuntimeException("查找合同 " + name + " 时发生错误", e);
        }
    }

    public List<ContractVo> findAllBySaleContract(ContractVo contract) {
        String parentCode = contract.getCode();
        if (StringUtils.isEmpty(parentCode)) {
            return List.of();
        }
        return findAll(ParamUtils.equal("parentCode", parentCode), Pageable.unpaged()).getContent();
    }

    public boolean checkContractPathInBasePath(ContractVo v) {
        if (!existsContractPath(v)) {
            return false;
        }
        File basePath = getBasePath();
        if (basePath == null || !basePath.exists()) {
            throw new IllegalArgumentException("basePath 不存在");
        }
        File path = new File(v.getPath());
        return path.getAbsolutePath().startsWith(basePath.getAbsolutePath());
    }

    public boolean existsContractPath(ContractVo v) {
        if (!org.springframework.util.StringUtils.hasText(v.getPath())) {
            return false;
        }

        File path = new File(v.getPath());
        return path.exists();
    }

    public boolean makePathAbsent(ContractVo contract) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Unimplemented method 'makePathAbsent'");
    }

    public List<ContractVo> findAllByCompanyVendor(VendorVo vendor, LocalDate beginDate, LocalDate endDate) {
        return findAll(ParamUtils.builder()
                .equals("company", vendor.getCompanyId())
                .between("setupDate", beginDate, endDate)
                .build(), Pageable.unpaged()).getContent();
    }

    public List<ContractVo> findAllSalesByProject(ProjectVo project) {
        return findAll(ParamUtils.builder()
                .equals("parentCode", "")
                .equals("project", project.getId()).build(),
                Pageable.unpaged()).getContent();
    }

    public ContractVo findSalesByProject(ProjectVo project) {
        Page<ContractVo> page = findAll(ParamUtils.builder()
                .equals("parentCode", "")
                .equals("project", project.getId()).build(), Pageable.ofSize(1));
        if (page.isEmpty()) {
            return null;
        }
        return page.getContent().getFirst();
    }

    public List<ContractVo> findAllByProject(ProjectVo project) {
        return findAll(ParamUtils.equal("project", project.getId()), Pageable.unpaged()).getContent();
    }

    public void syncContractFile(ContractFileVo contractFile, File outputFile, MessageHolder holder) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Unimplemented method 'syncContractFile'");
    }
}
