package com.ecep.contract.cloud.old;

import java.beans.PropertyDescriptor;
import java.io.File;
import java.time.Instant;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.ecep.contract.CompanyFileType;
import com.ecep.contract.ContractFileType;
import com.ecep.contract.SpringApp;
import com.ecep.contract.VendorType;
import com.ecep.contract.cloud.rk.CloudRkService;
import com.ecep.contract.cloud.tyc.CloudTycService;
import com.ecep.contract.ds.company.repository.CompanyContactRepository;
import com.ecep.contract.ds.company.repository.CompanyFileRepository;
import com.ecep.contract.ds.company.repository.CompanyOldNameRepository;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.contract.repository.ContractFileRepository;
import com.ecep.contract.ds.contract.repository.ContractRepository;
import com.ecep.contract.ds.customer.repository.CompanyCustomerFileRepository;
import com.ecep.contract.ds.customer.repository.CompanyCustomerRepository;
import com.ecep.contract.ds.other.service.SysConfService;
import com.ecep.contract.ds.vendor.repository.CompanyVendorRepository;
import com.ecep.contract.ds.vendor.service.CompanyVendorFileService;
import com.ecep.contract.model.CloudRk;
import com.ecep.contract.model.CloudTyc;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyContact;
import com.ecep.contract.model.CompanyContract;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerFile;
import com.ecep.contract.model.CompanyFile;
import com.ecep.contract.model.CompanyOldName;
import com.ecep.contract.model.CompanyVendor;
import com.ecep.contract.model.CompanyVendorFile;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractFile;

import jakarta.transaction.Transactional;

/**
 * 从老板APP的数据库中导入数据
 * <p>
 * 数据结构不同
 */
@Lazy
@Service
public class OldVersionService {
    private static final Logger logger = LoggerFactory.getLogger(OldVersionService.class);
    @Autowired
    private ContractFileRepository contractFileRepository;


    public enum Types {
        VENDOR, CUSTOMER
    }

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private SysConfService confService;
    @Lazy
    @Autowired
    private CompanyService companyService;
    @Autowired
    private CloudRkService cloudRkService;
    @Autowired
    private CloudTycService cloudTycService;
    @Autowired
    private CompanyContactRepository companyContactRepository;
    @Autowired
    private CompanyCustomerRepository companyCustomerRepository;
    @Autowired
    private CompanyVendorRepository companyVendorRepository;
    @Autowired
    private CompanyOldNameRepository companyOldNameRepository;
    @Autowired
    private ContractRepository contractRepository;
    @Autowired
    private CompanyFileRepository companyFileRepository;

    public Long countOfVendor() {
        return jdbcTemplate.queryForObject("select COUNT(*) from VENDOR;", Long.class);
    }

    public Stream<Map<String, Object>> queryAllVendorForStream() {
        return jdbcTemplate.queryForStream(
                "select ID,NAME,UNISCID,ENT_STATUS,ENT_TYPE,PATH_EXIST,PATH,TYPE," +
                        "DISTRICT,INDUSTRY,TELEPHONE,REG_ADDR,ADDRESS,REGISTERED_CAPITAL,REGISTERED_CAPITAL_CURRENCY," +
                        "LEGAL_REPRESENTATIVE,CLOUD_ID,TYC_ID,TYC_SCORE,OPERATION_PERIOD_BEGIN,OPERATION_PERIOD_END,MEMO," +
                        "SETUP_DATE,CREATED from VENDOR;",
                new ColumnMapRowMapper()
        );
    }

    public Long countOfVendorContract() {
        return jdbcTemplate.queryForObject("select COUNT(*) from VENDOR_CONTRACT;", Long.class);
    }

    public Stream<Map<String, Object>> queryAllVendorContractForStream() {
        return jdbcTemplate.queryForStream("select ID,NO,DIRECTORY from VENDOR_CONTRACT;", new ColumnMapRowMapper());
    }

    public List<Map<String, Object>> queryVendorContractFileByContractId(int contractId) {
        return jdbcTemplate.queryForList("select ID, CONTRACT_ID, TYPE, FILE, APPLY_DATE, MEMO from VENDOR_CONTRACT_APPROVAL where CONTRACT_ID=?;", contractId);
    }

    public Stream<Map<String, Object>> queryAllVendorContactForStream() {
        return jdbcTemplate.queryForStream("select NAME,PHONE,EMAIL,ADDRESS,VENDOR_ID as GID from VENDOR_CONTACT;", new ColumnMapRowMapper());
    }

    public Stream<Map<String, Object>> queryAllVendorOldNameForStream() {
        return jdbcTemplate.queryForStream("select NAME,PATH,VENDOR_ID as GID,MEMO from VENDOR_OLD_NAME;", new ColumnMapRowMapper());
    }

    public List<Map<String, Object>> queryVendorEvidenceByVendorId(int vendorId) {
        return jdbcTemplate.queryForList("select ID, TYPE, FILE_PATH, APPLY_DATE, EXPIRING_DATE from VENDOR_EVIDENCE where VENDOR_ID=?;", vendorId);
    }

    public List<Map<String, Object>> queryVendorEvalFormByVendorId(int vendorId) {
        return jdbcTemplate.queryForList("select ID, FILE_PATH, EDIT_FILE_PATH, SIGN_DATE,VALID from VENDOR_EVAL_FORM where VENDOR_ID=?;", vendorId);
    }

    @Transactional
    public int newCompanyVendor(String companyName) {
        Integer maxId = jdbcTemplate.queryForObject("select max(ID) from VENDOR;", Integer.class);
        if (maxId != null) {
            int nextId = maxId + 1;
            if (jdbcTemplate.update("INSERT INTO VENDOR (ID, NAME)values(?, ?);", nextId, companyName) > 0) {
                return nextId;
            }
        }
        return -1;
    }

    public Long countOfCustomer() {
        return jdbcTemplate.queryForObject("select COUNT(*) from CUSTOMER;", Long.class);
    }

    public Stream<Map<String, Object>> queryAllCustomerForStream() {
        return jdbcTemplate.queryForStream(
                "select ID,NAME,UNISCID,ENT_STATUS,ENT_TYPE,PATH_EXIST,PATH," +
                        "DISTRICT,INDUSTRY,TELEPHONE,REG_ADDR,ADDRESS,REGISTERED_CAPITAL," +
                        "LEGAL_REPRESENTATIVE,CLOUD_ID,TYC_ID,TYC_SCORE,OPERATION_PERIOD_BEGIN,OPERATION_PERIOD_END,MEMO," +
                        "SETUP_DATE,CREATED from CUSTOMER;",
                new ColumnMapRowMapper()
        );
    }

    public Long countOfCustomerContract() {
        return jdbcTemplate.queryForObject("select COUNT(*) from CUSTOMER_CONTRACT;", Long.class);
    }

    public Stream<Map<String, Object>> queryAllCustomerContractForStream() {
        return jdbcTemplate.queryForStream("select ID,NO,DIRECTORY from CUSTOMER_CONTRACT;", new ColumnMapRowMapper());
    }

    public List<Map<String, Object>> queryCustomerContractFileByContractId(int contractId) {
        return jdbcTemplate.queryForList("select ID, CONTRACT_ID, TYPE, FILE, APPLY_DATE, MEMO from CUSTOMER_CONTRACT_APPROVAL where CONTRACT_ID=?;", contractId);
    }

    public Stream<Map<String, Object>> queryAllCustomerContactForStream() {
        return jdbcTemplate.queryForStream("select NAME,PHONE,EMAIL,ADDRESS,CUSTOMER_ID as GID from CUSTOMER_CONTACT;", new ColumnMapRowMapper());
    }

    public Stream<Map<String, Object>> queryAllCustomerOldNameForStream() {
        return jdbcTemplate.queryForStream("select NAME,PATH,CUSTOMER_ID as GID,MEMO from CUSTOMER_OLD_NAME;", new ColumnMapRowMapper());
    }

    public List<Map<String, Object>> queryCustomerEvidenceByCustomerId(int customerId) {
        return jdbcTemplate.queryForList("select ID, TYPE, FILE_PATH, APPLY_DATE, EXPIRING_DATE from CUSTOMER_EVIDENCE where CUSTOMER_ID=?;", customerId);
    }

    public List<Map<String, Object>> queryCustomerEvalFormByCustomerId(int customerId) {
        return jdbcTemplate.queryForList("select ID, FILE_PATH, EDIT_FILE_PATH, SIGN_DATE, VALID from CUSTOMER_EVAL_FORM where CUSTOMER_ID=?;", customerId);
    }

    @Transactional
    public int newCompanyCustomer(String companyName) {
        Integer maxId = jdbcTemplate.queryForObject("select max(ID) from CUSTOMER;", Integer.class);
        if (maxId != null) {
            int nextId = maxId + 1;
            if (jdbcTemplate.update("INSERT INTO CUSTOMER (ID, NAME)values(?, ?);", nextId, companyName) > 0) {
                return nextId;
            }
        }
        return -1;
    }

    /**
     * 更新公司信息
     *
     * @param updater 要更新的公司对象
     * @param map     数据map
     */
    public boolean applyCompany(Company updater, Map<String, Object> map) {
        boolean changed = false;

        String[][] fieldMapping = new String[][]{
                {"entStatus", "ENT_STATUS"},
                {"entType", "ENT_TYPE"},
                {"district", "DISTRICT"},
                {"industry", "INDUSTRY"},
                {"telephone", "TELEPHONE"},
                {"regAddr", "REG_ADDR"},
                {"address", "ADDRESS"},
                {"registeredCapital", "REGISTERED_CAPITAL"},
                {"registeredCapitalCurrency", "REGISTERED_CAPITAL_CURRENCY"},
                {"legalRepresentative", "LEGAL_REPRESENTATIVE"},
                {"memo", "MEMO"}
        };

        java.sql.Date created = (java.sql.Date) map.get("CREATED");
        java.sql.Date operationPeriodBegin = (java.sql.Date) map.get("OPERATION_PERIOD_BEGIN");
        java.sql.Date operationPeriodEnd = (java.sql.Date) map.get("OPERATION_PERIOD_END");
        java.sql.Date setupDate = (java.sql.Date) map.get("SETUP_DATE");

        // PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(Company.class);

        for (String[] fieldMap : fieldMapping) {
            if (updateCompanyProperty(updater, fieldMap[0], map.get(fieldMap[1]))) {
                changed = true;
            }
        }

        if (setupDate != null) {
            if (updateCompanyProperty(updater, "setupDate", setupDate.toLocalDate())) {
                changed = true;
            }
        }
        if (operationPeriodBegin != null) {
            if (updateCompanyProperty(updater, "operationPeriodBegin", operationPeriodBegin.toLocalDate())) {
                changed = true;
            }
        }
        if (operationPeriodEnd != null) {
            if (updateCompanyProperty(updater, "operationPeriodEnd", operationPeriodEnd.toLocalDate())) {
                changed = true;
            }
        }

        if (created != null) {
            if (updateCompanyProperty(updater, "created", created.toLocalDate())) {
                changed = true;
            }
        }
        return changed;
    }

    private boolean updateCompanyProperty(Company updater, String field, Object newValue) {
        if (newValue == null) {
            return false;
        }
        PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(Company.class, field);
        if (descriptor == null) {
            logger.error("Company 的字段 {} 不存在,请确认.", field);
            return false;
        }
        try {
            Object oldValue = descriptor.getReadMethod().invoke(updater);
            if (!Objects.equals(oldValue, newValue)) {
                descriptor.getWriteMethod().invoke(updater, newValue);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    private void updateProperty(String input, Supplier<String> getter, Consumer<String> setter) {
        if (input != null) {
            if (!input.equals(getter.get())) {
                setter.accept(input);
            }
        }
    }

    /**
     * 应用联系人数据
     * <p>
     * {@link #queryAllVendorContactForStream()} {@link #queryAllCustomerContactForStream()}
     */
    public void applyContacts(Company updater, List<Map<String, Object>> contacts, File basePath) {
        if (contacts.isEmpty()) {
            return;
        }
        // 检索出公司下属的所有联系人
        List<CompanyContact> myContacts = companyContactRepository.findAllByCompany(updater);
        // 1. 先做数据库排重
        HashMap<String, CompanyContact> contactMap = new HashMap<>();
        for (CompanyContact contact : myContacts) {
            String key = CompanyContract.getContactKey(contact);
            if (contactMap.containsKey(key)) {
                // 有重复，删除，按List顺序，只保留第一个
                companyContactRepository.delete(contact);
                if (logger.isInfoEnabled()) {
                    logger.info("Duplicate CompanyContact, Delete {}", contact);
                }
            } else {
                // 名称记录到 contactMap 中
                contactMap.put(key, contact);
            }
        }

        // 2. 使用导入数据更新 数据中的 已存在的记录
        for (Map<String, Object> contact : contacts) {
            String key = CompanyContactUtils.getContactKey(contact);
            CompanyContact oldName1 = contactMap.get(key);
            if (oldName1 == null) {
                continue;
            }

            if (CompanyContactUtils.applyContactByMap(oldName1, contact)) {
                CompanyContact saved = companyContactRepository.save(oldName1);
                contactMap.put(key, saved);
            }
        }

        // 3. 移除导入的曾用名中删除数据库中已经存在的
        contacts.removeIf(m -> contactMap.containsKey(CompanyContactUtils.getContactKey(m)));

        // 4. 剩下的保存
        for (Map<String, Object> m : contacts) {
            String name = (String) m.get("NAME");
            if (!StringUtils.hasText(name)) {
                continue;
            }
            try {
                CompanyContact contact = new CompanyContact();
                CompanyContactUtils.applyContactByMap(contact, m);
                contact.setCompany(updater);
                companyContactRepository.save(contact);
                if (logger.isInfoEnabled()) {
                    logger.info("Create New CompanyContact {}", contact);
                }
            } catch (Exception e) {
                throw new RuntimeException("Unable Save " + m, e);
            }
        }
    }

    public void applyOldNames(Company updater, List<Map<String, Object>> oldNames, File basePath) {
        if (oldNames.isEmpty()) {
            return;
        }
        // fixed 移除和更新公司同名的曾用名
        oldNames.removeIf(m -> {
            String name = (String) m.get("NAME");
            if (name == null) {
                return true;
            }
            return name.equals(updater.getName());
        });

        // 检索出公司下属的所有曾用名
        List<CompanyOldName> myOldNames = companyOldNameRepository.findAllByCompanyId(updater.getId());
        // 1. 先做数据库排重
        HashMap<String, CompanyOldName> oldNameMap = new HashMap<>();
        for (CompanyOldName oldName : myOldNames) {
            String key = oldName.getName();
            if (oldNameMap.containsKey(key)) {
                // 有重复，删除，按List顺序，只保留第一个
                companyOldNameRepository.delete(oldName);
                if (logger.isInfoEnabled()) {
                    logger.info("Duplicate CompanyOldName, Delete {}", oldName);
                }
            } else {
                // 名称记录到 oldNameMap 中
                oldNameMap.put(key, oldName);
            }
        }

        // fixed 移除和更新公司同名的曾用名
        CompanyOldName mainName = oldNameMap.get(updater.getName());
        if (mainName != null) {
            companyOldNameRepository.delete(mainName);
            if (logger.isInfoEnabled()) {
                logger.info("Same Name as Company Name, Delete {}", mainName);
            }
        }


        // 2. 使用导入数据更新 数据中的 已存在的记录
        for (Map<String, Object> oldName : oldNames) {
            String key = (String) oldName.getOrDefault("NAME", null);
            CompanyOldName oldName1 = oldNameMap.get(key);
            if (oldName1 == null) {
                continue;
            }
            boolean modified = false;
            String oldNamePath = (String) oldName.get("PATH");
            String oldNameMemo = (String) oldName.get("MEMO");
            if (oldNamePath != null) {
                // 更新路径
                File dest = new File(basePath, oldNamePath);
                String absolutePath = dest.getAbsolutePath();
                if (!Objects.equals(oldName1.getPath(), absolutePath)) {
                    oldName1.setPath(absolutePath);
                    modified = true;
                }
            }
            if (oldNameMemo != null) {
                // 更新备注
                if (!Objects.equals(oldName1.getMemo(), oldNameMemo)) {
                    oldName1.setMemo(oldNameMemo);
                    modified = true;
                }
            }
            if (modified) {
                CompanyOldName saved = companyOldNameRepository.save(oldName1);
                oldNameMap.put(key, saved);
            }
        }

        // 3. 移除导入的曾用名中删除数据库中已经存在的
        oldNames.removeIf(m -> oldNameMap.containsKey((String) m.get("NAME")));

        // 4. 剩下的保存
        for (Map<String, Object> m : oldNames) {
            String name = (String) m.get("NAME");
            String memo = (String) m.get("MEMO");
            String path = (String) m.get("PATH");
            if (!StringUtils.hasText(name)) {
                continue;
            }

            try {
                CompanyOldName oldName = new CompanyOldName();
                oldName.setCompanyId(updater.getId());
                oldName.setName(name);
                oldName.setMemo(memo);
                oldName.setAmbiguity(false);
                if (StringUtils.hasText(path)) {
                    File dest = new File(basePath, path);
                    String absolutePath = dest.getAbsolutePath();
                    oldName.setPath(absolutePath);
                }
                companyOldNameRepository.save(oldName);
                if (logger.isInfoEnabled()) {
                    logger.info("Create New CompanyOldName {}", oldName);
                }
            } catch (Exception e) {
                throw new RuntimeException("Unable Save " + m, e);
            }
        }
    }

    /**
     * 应用天眼查和相关方平台的Id
     */
    private void applyCloudRkAndTyc(Company updater, Map<String, Object> map) {
        String cloudRkId = (String) map.getOrDefault("CLOUD_ID", null);
        String cloudTycId = (String) map.getOrDefault("TYC_ID", null);
        Integer tycScore = (Integer) map.getOrDefault("TYC_SCORE", null);

        // fixed when new company before save will throw exception
        if (cloudRkId != null) {
            CloudRk cloudRk = cloudRkService.getOrCreateCloudRk(updater);
            if (!Objects.equals(cloudRk.getCloudId(), cloudRkId)) {
                cloudRk.setCloudId(cloudRkId);
                cloudRkService.save(cloudRk);
            }
        }
        if (cloudTycId != null) {
            boolean tycModified = false;
            CloudTyc cloudTyc = cloudTycService.getOrCreateCloudTyc(updater);
            if (!Objects.equals(cloudTyc.getCloudId(), cloudTycId)) {
                cloudTyc.setCloudId(cloudTycId);
                tycModified = true;
            }
            if (!Objects.equals(cloudTyc.getScore(), tycScore)) {
                cloudTyc.setScore(tycScore);
                tycModified = true;
            }
            if (tycModified) {
                cloudTycService.save(cloudTyc);
            }
        }
    }

    public void applyVendorOrCustomer(Company updater, Types type, Map<String, Object> map, File basePath) {
        Integer id = (Integer) map.get("ID");
        String path = (String) map.get("PATH");
        String absolutePath = null;
        if (path != null) {
            File dest = new File(basePath, path);
            absolutePath = dest.getAbsolutePath();
        }
        if (type == Types.VENDOR) {
            String vendorType = (String) map.get("TYPE");
            boolean changed = false;
            CompanyVendor companyVendor = companyVendorRepository.findByCompany(updater).orElseGet(() -> {
                CompanyVendor vendor = new CompanyVendor();
                vendor.setId(id);
                vendor.setCompany(updater);
                vendor.setCreated(Instant.now());
                return vendor;
            });

            if (StringUtils.hasText(vendorType)) {
                VendorType t = VendorType.valueOf(vendorType);
                if (!Objects.equals(t, companyVendor.getType())) {
                    companyVendor.setType(t);
                    changed = true;
                }
            }

            if (companyVendor.getCompany() == null) {
                companyVendor.setCompany(updater);
                changed = true;
            }

            if (!Objects.equals(absolutePath, companyVendor.getPath())) {
                companyVendor.setPath(absolutePath);
                changed = true;
            }

            if (changed) {
                companyVendorRepository.save(companyVendor);
            }

            CompanyVendorFileService fileService = SpringApp.getBean(CompanyVendorFileService.class);

            // 1. 先做数据库排重
            List<CompanyVendorFile> files = fileService.findAllByVendor(companyVendor);
            HashMap<String, CompanyVendorFile> fileMap = new HashMap<>();
            for (CompanyVendorFile vendorFile : files) {
                String key = vendorFile.getFilePath();
                if (fileMap.containsKey(key)) {
                    // 有重复，删除，按List顺序，只保留第一个
                    fileService.delete(vendorFile);
                    if (logger.isInfoEnabled()) {
                        logger.info("Duplicate CompanyVendorFile, Delete {}", vendorFile);
                    }
                } else {
                    // 名称记录到 fileMap 中
                    fileMap.put(key, vendorFile);
                }
            }

            // 2. 使用导入数据更新 数据中的 已存在的记录
            List<Map<String, Object>> rs = queryVendorEvalFormByVendorId(id);
            for (Map<String, Object> m : rs) {
                String key = CompanyVendorFileUtils.getVendorFileKey(m);
                CompanyVendorFile vendorFile = fileMap.get(key);
                if (vendorFile == null) {
                    continue;
                }

                if (CompanyVendorFileUtils.applyVendorFileByMap(vendorFile, m)) {
                    CompanyVendorFile saved = fileService.save(vendorFile);
                    fileMap.put(key, saved);
                }
            }

            // 3. 移除导入的数据库中已经存在的
            rs.removeIf(m -> fileMap.containsKey(CompanyVendorFileUtils.getVendorFileKey(m)));

            // 4. 剩下的保存
            for (Map<String, Object> m : rs) {
                String key = CompanyVendorFileUtils.getVendorFileKey(m);
                if (!StringUtils.hasText(key)) {
                    continue;
                }
                try {
                    CompanyVendorFile vendorFile = new CompanyVendorFile();
                    CompanyVendorFileUtils.applyVendorFileByMap(vendorFile, m);
                    vendorFile.setVendor(companyVendor);
                    fileService.save(vendorFile);
                    if (logger.isInfoEnabled()) {
                        logger.info("Create New CompanyVendorFile {}", vendorFile);
                    }
                } catch (Exception e) {
                    throw new RuntimeException("Unable Save " + m, e);
                }
            }

        } else if (type == Types.CUSTOMER) {
            boolean changed = false;
            CompanyCustomer companyCustomer = companyCustomerRepository.findByCompany(updater).orElseGet(() -> {
                CompanyCustomer customer = new CompanyCustomer();
                customer.setId(id);
                customer.setCompany(updater);
                customer.setCreated(Instant.now());
                return customer;
            });
            if (companyCustomer.getCompany() == null) {
                companyCustomer.setCompany(updater);
                changed = true;
            }
            if (!Objects.equals(absolutePath, companyCustomer.getPath())) {
                companyCustomer.setPath(absolutePath);
                changed = true;
            }
            if (changed) {
                companyCustomerRepository.save(companyCustomer);
            }

            CompanyCustomerFileRepository fileRepository = SpringApp.getBean(CompanyCustomerFileRepository.class);

            // 1. 先做数据库排重
            List<CompanyCustomerFile> files = fileRepository.findAllByCustomer(companyCustomer);
            HashMap<String, CompanyCustomerFile> fileMap = new HashMap<>();
            for (CompanyCustomerFile customerFile : files) {
                String key = customerFile.getFilePath();
                if (fileMap.containsKey(key)) {
                    // 有重复，删除，按List顺序，只保留第一个
                    fileRepository.delete(customerFile);
                    if (logger.isInfoEnabled()) {
                        logger.info("Duplicate CompanyCustomerFile, Delete {}", customerFile);
                    }
                } else {
                    // 名称记录到 fileMap 中
                    fileMap.put(key, customerFile);
                }
            }

            // 2. 使用导入数据更新 数据中的 已存在的记录
            List<Map<String, Object>> rs = queryCustomerEvalFormByCustomerId(id);
            for (Map<String, Object> m : rs) {
                String key = CompanyCustomerFileUtils.getCustomerFileKey(m);
                CompanyCustomerFile vendorFile = fileMap.get(key);
                if (vendorFile == null) {
                    continue;
                }

                if (CompanyCustomerFileUtils.applyCustomerFileByMap(vendorFile, m)) {
                    CompanyCustomerFile saved = fileRepository.save(vendorFile);
                    fileMap.put(key, saved);
                }
            }

            // 3. 移除导入的数据库中已经存在的
            rs.removeIf(m -> fileMap.containsKey(CompanyCustomerFileUtils.getCustomerFileKey(m)));

            // 4. 剩下的保存
            for (Map<String, Object> m : rs) {
                String key = CompanyVendorFileUtils.getVendorFileKey(m);
                if (!StringUtils.hasText(key)) {
                    continue;
                }
                try {
                    CompanyCustomerFile customerFile = new CompanyCustomerFile();
                    CompanyCustomerFileUtils.applyCustomerFileByMap(customerFile, m);
                    customerFile.setCustomer(companyCustomer);
                    fileRepository.save(customerFile);
                    if (logger.isInfoEnabled()) {
                        logger.info("Create New CompanyCustomerFile {}", customerFile);
                    }
                } catch (Exception e) {
                    throw new RuntimeException("Unable Save " + m, e);
                }
            }
        }
    }

    public Company syncVendor(
            Map<String, Object> map, File basePath,
            Map<Object, List<Map<String, Object>>> oldNameGroupedMap,
            Map<Object, List<Map<String, Object>>> contactGroupedMap
    ) {
        String uniscid = (String) map.get("UNISCID");
        if (StringUtils.hasText(uniscid)) {
            return syncVendorOrCustomerByUniscid(map, Types.VENDOR, basePath, oldNameGroupedMap, contactGroupedMap);
        } else {
            return syncVendorOrCustomerByName(map, Types.VENDOR, basePath, oldNameGroupedMap, contactGroupedMap);
        }
    }

    public Company syncCustomer(
            Map<String, Object> map, File basePath,
            Map<Object, List<Map<String, Object>>> oldNameGroupedMap,
            Map<Object, List<Map<String, Object>>> contactGroupedMap
    ) {
        String uniscid = (String) map.get("UNISCID");
        if (StringUtils.hasText(uniscid)) {
            return syncVendorOrCustomerByUniscid(map, Types.CUSTOMER, basePath, oldNameGroupedMap, contactGroupedMap);
        } else {
            return syncVendorOrCustomerByName(map, Types.CUSTOMER, basePath, oldNameGroupedMap, contactGroupedMap);
        }
    }

    private Company syncVendorOrCustomerByName(
            Map<String, Object> map, Types type, File basePath,
            Map<Object, List<Map<String, Object>>> oldNameGroupedMap,
            Map<Object, List<Map<String, Object>>> contactGroupedMap
    ) {
        Integer id = (Integer) map.get("ID");
        String name = (String) map.get("NAME");
        if (name.equals("散户")) {
            return null;
        }
        Company updater = companyService.findAndRemoveDuplicateCompanyByNameOrAbbName(name, null);
        if (updater == null) {
            if (logger.isDebugEnabled()) {
                logger.debug("No match Name {} , map = {}", name, map);
            }
            return null;
        }
        boolean updaterModified = false;

        List<Map<String, Object>> oldNameList;
        {
            List<Map<String, Object>> m = oldNameGroupedMap.get(id);
            if (m != null) {
                oldNameList = new ArrayList<>(m);
            } else {
                oldNameList = new ArrayList<>();
            }
        }

        // fixed 当名称不一致时
        if (!updater.getName().equals(name)) {
            // 把当前名称存入 曾用名 中
            Map<String, Object> m = new HashMap<>();
            m.put("NAME", name);
            oldNameList.add(m);
        }

        if (applyCompany(updater, map)) {
            updaterModified = true;

        }
        applyCloudRkAndTyc(updater, map);

        applyVendorOrCustomer(updater, type, map, basePath);
        applyOldNames(updater, oldNameList, basePath);

        List<Map<String, Object>> contacts;
        {
            List<Map<String, Object>> m = contactGroupedMap.get(id);
            if (m != null) {
                contacts = new ArrayList<>(m);
            } else {
                contacts = new ArrayList<>();
            }
        }
        applyContacts(updater, contacts, basePath);
        if (syncEvidence(updater, type, id)) {
            updaterModified = true;
        }
        if (updaterModified) {
            updater = companyService.save(updater);
        }
        return updater;
    }

    private boolean syncEvidence(Company updater, Types type, Integer id) {
        List<Map<String, Object>> importRs = type == Types.VENDOR ? queryVendorEvidenceByVendorId(id) : queryCustomerEvidenceByCustomerId(id);
        if (importRs.isEmpty()) {
            return false;
        }
        boolean updaterChanged = companyService.makePathAbsent(updater);
        String path = updater.getPath();
        if (!StringUtils.hasText(path)) {
            if (logger.isInfoEnabled()) {
                logger.info("Company home not exist {}", updater);
            }
            return false;
        }
        File companyPath = new File(path);

        // 检索出公司下属的所有文件
        List<CompanyFile> existRs = companyFileRepository.findByCompany(updater);
        // 1. 先做数据库排重
        HashMap<String, CompanyFile> existMap = new HashMap<>();
        for (CompanyFile companyFile : existRs) {
            String key = companyFile.getFilePath();
            if (existMap.containsKey(key)) {
                // 有重复，删除，按List顺序，只保留第一个
                companyFileRepository.delete(companyFile);
                if (logger.isInfoEnabled()) {
                    logger.info("Duplicate CompanyFile, Delete {}", companyFile);
                }
            } else {
                // 名称记录到 existMap 中
                existMap.put(key, companyFile);
            }
        }

        // 2. 使用导入数据更新 数据中的 已存在的记录
        for (Map<String, Object> rs : importRs) {
            // ID, TYPE, FILE_PATH, APPLY_DATE, EXPIRING_DATE
            String key = (String) rs.get("FILE_PATH");
            CompanyFile oldName1 = existMap.get(key);
            if (oldName1 == null) {
                continue;
            }
            boolean modified = false;

            String rsType = (String) rs.get("TYPE");
            java.sql.Date rsApplyDate = (java.sql.Date) rs.get("APPLY_DATE");
            java.sql.Date rsExpiringDate = (java.sql.Date) rs.get("EXPIRING_DATE");
            if (rsType != null) {
                if (oldName1.getType() == null || !Objects.equals(oldName1.getType().name(), rsType)) {
                    oldName1.setType(CompanyFileType.valueOf(rsType));
                    modified = true;
                }
            }
            if (rsApplyDate != null) {
                LocalDate localDate = rsApplyDate.toLocalDate();
                if (!Objects.equals(oldName1.getApplyDate(), localDate)) {
                    oldName1.setApplyDate(localDate);
                    modified = true;
                }
            }
            if (rsExpiringDate != null) {
                LocalDate localDate = rsExpiringDate.toLocalDate();
                if (!Objects.equals(oldName1.getExpiringDate(), localDate)) {
                    oldName1.setExpiringDate(localDate);
                    modified = true;
                }
            }

            //TODO 移动文件,删除记录


            if (modified) {
                CompanyFile saved = companyFileRepository.save(oldName1);
                existMap.put(key, saved);
            }
        }

        // 3. 移除导入的曾用名中删除数据库中已经存在的
        importRs.removeIf(m -> existMap.containsKey((String) m.get("FILE_PATH")));

        // 4. 剩下的保存
        for (Map<String, Object> m : importRs) {
            String rsFilePath = (String) m.get("FILE_PATH");
            String rsType = (String) m.get("TYPE");
            java.sql.Date rsApplyDate = (java.sql.Date) m.get("APPLY_DATE");
            java.sql.Date rsExpiringDate = (java.sql.Date) m.get("EXPIRING_DATE");

            if (!StringUtils.hasText(rsFilePath)) {
                continue;
            }

            // 如果文件已经不在时,跳过
            File file = new File(rsFilePath);
            if (!file.exists()) {
                continue;
            }

            File dest = new File(companyPath, file.getName());
            if (!file.renameTo(dest)) {
                continue;
            }

            try {
                CompanyFile companyFile = new CompanyFile();
                companyFile.setCompany(updater);
                if (StringUtils.hasText(rsType)) {
                    companyFile.setType(CompanyFileType.valueOf(rsType));
                }
                companyFile.setFilePath(dest.getAbsolutePath());
                if (rsApplyDate != null) {
                    companyFile.setApplyDate(rsApplyDate.toLocalDate());
                }
                if (rsExpiringDate != null) {
                    companyFile.setExpiringDate(rsExpiringDate.toLocalDate());
                }
                companyFileRepository.save(companyFile);
                if (logger.isInfoEnabled()) {
                    logger.info("Create New CompanyFile {}", companyFile);
                }
            } catch (Exception e) {
                throw new RuntimeException("Unable Save " + m, e);
            }
        }
        return updaterChanged;
    }

    private Company syncVendorOrCustomerByUniscid(
            Map<String, Object> map, Types type, File basePath,
            Map<Object, List<Map<String, Object>>> oldNameGroupedMap,
            Map<Object, List<Map<String, Object>>> contactGroupedMap
    ) {
        Integer id = (Integer) map.get("ID");
        String uniscid = (String) map.get("UNISCID");
        String name = (String) map.get("NAME");

        Company updater = companyService.findAndRemoveDuplicateCompanyByUniscid(uniscid);
        boolean updaterModified = false;
        if (updater == null) {
            // 没有记录
            if (logger.isDebugEnabled()) {
                logger.debug("Create New Company by uniscid={}", uniscid);
            }
            updater = new Company();
            updater.setName(name);
            updater.setUniscid(uniscid);
            updaterModified = true;
        }

        List<Map<String, Object>> oldNameList;
        {
            List<Map<String, Object>> m = oldNameGroupedMap.get(id);
            if (m != null) {
                oldNameList = new ArrayList<>(m);
            } else {
                oldNameList = new ArrayList<>();
            }
        }

        // fixed 当名称不一致时
        if (!updater.getName().equals(name)) {
            // 把当前名称存入 曾用名 中
            Map<String, Object> m = new HashMap<>();
            m.put("NAME", name);
            oldNameList.add(m);
        }

        if (applyCompany(updater, map)) {
            updaterModified = true;
        }
        if (updaterModified) {
            updater = companyService.save(updater);
        }
        applyCloudRkAndTyc(updater, map);

        applyVendorOrCustomer(updater, type, map, basePath);
        applyOldNames(updater, oldNameList, basePath);

        List<Map<String, Object>> contacts;
        {
            List<Map<String, Object>> m = contactGroupedMap.get(id);
            if (m != null) {
                contacts = new ArrayList<>(m);
            } else {
                contacts = new ArrayList<>();
            }
        }
        applyContacts(updater, contacts, basePath);
        if (syncEvidence(updater, type, id)) {
            updater = companyService.save(updater);
        }
        return updater;
    }

    public Contract syncCustomerContract(Map<String, Object> map) {
        Integer id = (Integer) map.get("ID");
        Contract contract = syncContract(map);
        syncContractFile(Types.CUSTOMER, contract, id);
        return contract;
    }

    public Contract syncVendorContract(Map<String, Object> map) {
        Integer id = (Integer) map.get("ID");
        Contract contract = syncContract(map);
        syncContractFile(Types.VENDOR, contract, id);
        return contract;
    }

    private void syncContractFile(Types type, Contract contract, Integer id) {
        List<Map<String, Object>> importRs = type == Types.VENDOR ?
                queryVendorContractFileByContractId(id) : queryCustomerContractFileByContractId(id);
        if (importRs.isEmpty()) {
            return;
        }


        // 检索出公司下属的所有文件
        List<ContractFile> existRs = contractFileRepository.findByContract(contract);
        // 1. 先做数据库排重
        HashMap<String, ContractFile> existMap = new HashMap<>();
        for (ContractFile contractFile : existRs) {
            String key = contractFile.getFileName();
            if (existMap.containsKey(key)) {
                // 有重复，删除，按List顺序，只保留第一个
                contractFileRepository.delete(contractFile);
                if (logger.isInfoEnabled()) {
                    logger.info("Duplicate ContractFile, Delete {}", contractFile);
                }
            } else {
                // 名称记录到 existMap 中
                existMap.put(key, contractFile);
            }
        }

        // 2. 使用导入数据更新 数据中的 已存在的记录
        for (Map<String, Object> rs : importRs) {
            // ID, CONTRACT_ID, TYPE, FILE, APPLY_DATE, MEMO
            String key = (String) rs.get("FILE");
            ContractFile oldName1 = existMap.get(key);
            if (oldName1 == null) {
                continue;
            }
            boolean modified = false;

            String rsType = (String) rs.get("TYPE");
            java.sql.Date rsApplyDate = (java.sql.Date) rs.get("APPLY_DATE");
            String memo = (String) rs.get("MEMO");
            if (rsType != null) {
                if (oldName1.getType() == null || !Objects.equals(oldName1.getType().name(), rsType)) {
                    oldName1.setType(ContractFileType.valueOf(rsType));
                    modified = true;
                }
            }
            if (rsApplyDate != null) {
                LocalDate localDate = rsApplyDate.toLocalDate();
                if (!Objects.equals(oldName1.getApplyDate(), localDate)) {
                    oldName1.setApplyDate(localDate);
                    modified = true;
                }
            }
            if (memo != null) {
                if (!Objects.equals(oldName1.getDescription(), memo)) {
                    oldName1.setDescription(memo);
                    modified = true;
                }
            }

            if (modified) {
                ContractFile saved = contractFileRepository.save(oldName1);
                existMap.put(key, saved);
            }
        }

        // 3. 移除导入的曾用名中删除数据库中已经存在的
        importRs.removeIf(m -> existMap.containsKey((String) m.get("FILE")));

        // 4. 剩下的保存
        for (Map<String, Object> m : importRs) {
            String rsFile = (String) m.get("FILE");
            String rsType = (String) m.get("TYPE");
            java.sql.Date rsApplyDate = (java.sql.Date) m.get("APPLY_DATE");
            String memo = (String) m.get("MEMO");
            try {
                ContractFile contractFile = new ContractFile();
                contractFile.setContract(contract);
                if (StringUtils.hasText(rsType)) {
                    contractFile.setType(ContractFileType.valueOf(rsType));
                }
                if (StringUtils.hasText(rsFile)) {
                    contractFile.setFileName(rsFile);
                }
                if (rsApplyDate != null) {
                    contractFile.setApplyDate(rsApplyDate.toLocalDate());
                }
                if (memo != null) {
                    contractFile.setDescription(memo);
                }
                contractFileRepository.save(contractFile);
                if (logger.isInfoEnabled()) {
                    logger.info("Create New ContractFile {}", contractFile);
                }
            } catch (Exception e) {
                throw new RuntimeException("Unable Save " + m, e);
            }
        }
    }


    public Contract syncContract(Map<String, Object> map) {
        String no = String.valueOf(map.get("NO"));
        String path = String.valueOf(map.get("DIRECTORY"));
        if (!StringUtils.hasText(path)) {
            return null;
        }
        AtomicReference<Contract> reference = new AtomicReference<>();
        contractRepository.findByCode(no).ifPresentOrElse(contract -> {
            if (!Objects.equals(contract.getPath(), path)) {
                contract.setPath(path);
                Contract saved = contractRepository.save(contract);
                reference.set(saved);
            } else {
                reference.set(contract);
            }
        }, () -> {
            if (logger.isWarnEnabled()) {
                logger.warn("No match Contract for {}", no);
            }
        });


        return reference.get();
    }
}
