package com.ruoyi.credit.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.ruoyi.credit.domain.BankInstitution;
import com.ruoyi.credit.domain.ConsistencyCheckResult;
import com.ruoyi.credit.domain.DataDifference;
import com.ruoyi.credit.domain.UnifiedBankData;
import com.ruoyi.credit.service.IBankDataConsistencyService;
import com.ruoyi.credit.service.IBankInstitutionService;
import com.ruoyi.credit.service.IUnifiedBankService;

/**
 * 银行数据一致性服务实现类
 * 
 * @author ruoyi
 * @date 2025-12-25
 */
@Service
public class BankDataConsistencyServiceImpl implements IBankDataConsistencyService 
{
    private static final Logger logger = LoggerFactory.getLogger(BankDataConsistencyServiceImpl.class);
    
    @Autowired
    private IBankInstitutionService bankInstitutionService;
    
    @Autowired
    private IUnifiedBankService unifiedBankService;

    /** 关键字段列表 */
    private static final String[] CRITICAL_FIELDS = {
        "bankName", "status", "cooperationStatus", "interestRate", "baseInterestRate"
    };

    @Override
    public ConsistencyCheckResult checkDataConsistency()
    {
        logger.info("开始执行银行数据一致性检查");
        long startTime = System.currentTimeMillis();
        
        try {
            // 获取银行管理界面的银行数据
            List<BankInstitution> managementBanks = bankInstitutionService.selectBankInstitutionList(new BankInstitution());
            
            // 获取服务周期贷款系统的银行数据
            List<UnifiedBankData> loanSystemBanks = unifiedBankService.convertFromServicePeriodLoanData(1L, 12);
            
            // 比较数据并生成差异列表
            List<DataDifference> differences = compareAllBankData(managementBanks, loanSystemBanks);
            
            // 计算一致性结果
            int totalBanks = Math.max(managementBanks.size(), loanSystemBanks.size());
            int inconsistentBanks = (int) differences.stream()
                .map(DataDifference::getBankId)
                .distinct()
                .count();
            
            boolean isConsistent = differences.isEmpty();
            
            ConsistencyCheckResult result = new ConsistencyCheckResult(isConsistent, totalBanks, inconsistentBanks, differences);
            result.setCheckDurationMs(System.currentTimeMillis() - startTime);
            
            logger.info("银行数据一致性检查完成: 总银行数={}, 不一致银行数={}, 差异数={}, 耗时={}ms", 
                       totalBanks, inconsistentBanks, differences.size(), result.getCheckDurationMs());
            
            return result;
            
        } catch (Exception e) {
            logger.error("银行数据一致性检查失败", e);
            ConsistencyCheckResult result = ConsistencyCheckResult.createFailedResult("数据一致性检查执行失败: " + e.getMessage());
            result.setCheckDurationMs(System.currentTimeMillis() - startTime);
            return result;
        }
    }

    @Override
    public ConsistencyCheckResult checkBankDataConsistency(Long bankId)
    {
        logger.info("开始检查指定银行数据一致性: bankId={}", bankId);
        long startTime = System.currentTimeMillis();
        
        try {
            if (bankId == null) {
                return ConsistencyCheckResult.createFailedResult("银行ID不能为空");
            }
            
            // 获取银行管理界面的银行数据
            BankInstitution managementBank = bankInstitutionService.selectBankInstitutionByBankId(bankId);
            
            // 获取服务周期贷款系统的银行数据
            List<UnifiedBankData> loanSystemBanks = unifiedBankService.convertFromServicePeriodLoanData(1L, 12);
            UnifiedBankData loanSystemBank = loanSystemBanks.stream()
                .filter(bank -> bankId.equals(bank.getBankId()))
                .findFirst()
                .orElse(null);
            
            // 比较单个银行数据
            List<DataDifference> differences = compareSingleBankData(managementBank, loanSystemBank);
            
            boolean isConsistent = differences.isEmpty();
            int inconsistentBanks = isConsistent ? 0 : 1;
            
            ConsistencyCheckResult result = new ConsistencyCheckResult(isConsistent, 1, inconsistentBanks, differences);
            result.setCheckDurationMs(System.currentTimeMillis() - startTime);
            
            logger.info("指定银行数据一致性检查完成: bankId={}, 是否一致={}, 差异数={}", 
                       bankId, isConsistent, differences.size());
            
            return result;
            
        } catch (Exception e) {
            logger.error("指定银行数据一致性检查失败: bankId={}", bankId, e);
            ConsistencyCheckResult result = ConsistencyCheckResult.createFailedResult("银行数据一致性检查失败: " + e.getMessage());
            result.setCheckDurationMs(System.currentTimeMillis() - startTime);
            return result;
        }
    }

    @Override
    public List<DataDifference> getDataDifferences()
    {
        logger.info("获取所有银行数据差异");
        
        try {
            ConsistencyCheckResult result = checkDataConsistency();
            return result.getDifferences() != null ? result.getDifferences() : new ArrayList<>();
            
        } catch (Exception e) {
            logger.error("获取银行数据差异失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    public List<DataDifference> getBankDataDifferences(Long bankId)
    {
        logger.info("获取指定银行数据差异: bankId={}", bankId);
        
        try {
            ConsistencyCheckResult result = checkBankDataConsistency(bankId);
            return result.getDifferences() != null ? result.getDifferences() : new ArrayList<>();
            
        } catch (Exception e) {
            logger.error("获取指定银行数据差异失败: bankId={}", bankId, e);
            return new ArrayList<>();
        }
    }

    @Override
    public Map<String, Object> generateConsistencyReport()
    {
        logger.info("生成银行数据一致性报告");
        
        try {
            ConsistencyCheckResult result = checkDataConsistency();
            
            Map<String, Object> report = new HashMap<>();
            report.put("checkTime", result.getCheckTime());
            report.put("checkDurationMs", result.getCheckDurationMs());
            report.put("isConsistent", result.isConsistent());
            report.put("totalBanks", result.getTotalBanks());
            report.put("inconsistentBanks", result.getInconsistentBanks());
            report.put("consistencyPercentage", result.getConsistencyPercentage());
            report.put("checkStatus", result.getCheckStatus());
            
            // 按严重程度分组差异
            if (result.getDifferences() != null) {
                Map<String, List<DataDifference>> differencesBySeverity = result.getDifferences().stream()
                    .collect(Collectors.groupingBy(DataDifference::getSeverity));
                report.put("differencesBySeverity", differencesBySeverity);
                
                // 按差异类型分组
                Map<String, List<DataDifference>> differencesByType = result.getDifferences().stream()
                    .collect(Collectors.groupingBy(DataDifference::getDifferenceType));
                report.put("differencesByType", differencesByType);
                
                // 统计各字段的差异数量
                Map<String, Long> fieldDifferenceCount = result.getDifferences().stream()
                    .collect(Collectors.groupingBy(DataDifference::getFieldName, Collectors.counting()));
                report.put("fieldDifferenceCount", fieldDifferenceCount);
            }
            
            logger.info("银行数据一致性报告生成完成");
            return report;
            
        } catch (Exception e) {
            logger.error("生成银行数据一致性报告失败", e);
            Map<String, Object> errorReport = new HashMap<>();
            errorReport.put("checkTime", new Date());
            errorReport.put("checkStatus", "FAILED");
            errorReport.put("errorMessage", "报告生成失败: " + e.getMessage());
            return errorReport;
        }
    }

    @Override
    public Map<String, Object> getConsistencyStatistics()
    {
        logger.info("获取银行数据一致性统计信息");
        
        try {
            ConsistencyCheckResult result = checkDataConsistency();
            
            Map<String, Object> statistics = new HashMap<>();
            statistics.put("totalBanks", result.getTotalBanks());
            statistics.put("consistentBanks", result.getTotalBanks() - result.getInconsistentBanks());
            statistics.put("inconsistentBanks", result.getInconsistentBanks());
            statistics.put("consistencyPercentage", result.getConsistencyPercentage());
            statistics.put("totalDifferences", result.getDifferences() != null ? result.getDifferences().size() : 0);
            
            if (result.getDifferences() != null) {
                long highSeverityCount = result.getDifferences().stream()
                    .mapToLong(diff -> DataDifference.SEVERITY_HIGH.equals(diff.getSeverity()) ? 1 : 0)
                    .sum();
                statistics.put("highSeverityDifferences", highSeverityCount);
                
                long mediumSeverityCount = result.getDifferences().stream()
                    .mapToLong(diff -> DataDifference.SEVERITY_MEDIUM.equals(diff.getSeverity()) ? 1 : 0)
                    .sum();
                statistics.put("mediumSeverityDifferences", mediumSeverityCount);
                
                long lowSeverityCount = result.getDifferences().stream()
                    .mapToLong(diff -> DataDifference.SEVERITY_LOW.equals(diff.getSeverity()) ? 1 : 0)
                    .sum();
                statistics.put("lowSeverityDifferences", lowSeverityCount);
            }
            
            statistics.put("lastCheckTime", result.getCheckTime());
            statistics.put("checkStatus", result.getCheckStatus());
            
            return statistics;
            
        } catch (Exception e) {
            logger.error("获取银行数据一致性统计信息失败", e);
            Map<String, Object> errorStats = new HashMap<>();
            errorStats.put("checkStatus", "FAILED");
            errorStats.put("errorMessage", "统计信息获取失败: " + e.getMessage());
            return errorStats;
        }
    }

    @Override
    public ConsistencyCheckResult checkCriticalFieldsConsistency()
    {
        logger.info("开始检查关键字段一致性");
        long startTime = System.currentTimeMillis();
        
        try {
            // 获取银行管理界面的银行数据
            List<BankInstitution> managementBanks = bankInstitutionService.selectBankInstitutionList(new BankInstitution());
            
            // 获取服务周期贷款系统的银行数据
            List<UnifiedBankData> loanSystemBanks = unifiedBankService.convertFromServicePeriodLoanData(1L, 12);
            
            // 只比较关键字段
            List<DataDifference> differences = compareAllBankData(managementBanks, loanSystemBanks).stream()
                .filter(diff -> isCriticalField(diff.getFieldName()))
                .collect(Collectors.toList());
            
            int totalBanks = Math.max(managementBanks.size(), loanSystemBanks.size());
            int inconsistentBanks = (int) differences.stream()
                .map(DataDifference::getBankId)
                .distinct()
                .count();
            
            boolean isConsistent = differences.isEmpty();
            
            ConsistencyCheckResult result = new ConsistencyCheckResult(isConsistent, totalBanks, inconsistentBanks, differences);
            result.setCheckDurationMs(System.currentTimeMillis() - startTime);
            
            logger.info("关键字段一致性检查完成: 总银行数={}, 不一致银行数={}, 关键字段差异数={}", 
                       totalBanks, inconsistentBanks, differences.size());
            
            return result;
            
        } catch (Exception e) {
            logger.error("关键字段一致性检查失败", e);
            ConsistencyCheckResult result = ConsistencyCheckResult.createFailedResult("关键字段一致性检查失败: " + e.getMessage());
            result.setCheckDurationMs(System.currentTimeMillis() - startTime);
            return result;
        }
    }

    @Override
    public boolean validateConsistencyResult(ConsistencyCheckResult result)
    {
        if (result == null) {
            logger.warn("一致性检查结果为空");
            return false;
        }
        
        // 检查基本字段
        if (result.getTotalBanks() < 0 || result.getInconsistentBanks() < 0) {
            logger.warn("一致性检查结果数据异常: totalBanks={}, inconsistentBanks={}", 
                       result.getTotalBanks(), result.getInconsistentBanks());
            return false;
        }
        
        if (result.getInconsistentBanks() > result.getTotalBanks()) {
            logger.warn("不一致银行数量超过总银行数量: inconsistentBanks={}, totalBanks={}", 
                       result.getInconsistentBanks(), result.getTotalBanks());
            return false;
        }
        
        // 检查一致性逻辑
        boolean hasDifferences = result.getDifferences() != null && !result.getDifferences().isEmpty();
        if (result.isConsistent() && hasDifferences) {
            logger.warn("一致性结果矛盾: isConsistent=true但存在差异");
            return false;
        }
        
        if (!result.isConsistent() && !hasDifferences && result.getInconsistentBanks() > 0) {
            logger.warn("一致性结果矛盾: isConsistent=false但无差异详情");
            return false;
        }
        
        return true;
    }

    /**
     * 比较所有银行数据
     */
    private List<DataDifference> compareAllBankData(List<BankInstitution> managementBanks, 
                                                   List<UnifiedBankData> loanSystemBanks)
    {
        List<DataDifference> differences = new ArrayList<>();
        
        // 创建贷款系统银行数据的映射
        Map<Long, UnifiedBankData> loanSystemBankMap = loanSystemBanks.stream()
            .filter(bank -> bank.getBankId() != null)
            .collect(Collectors.toMap(UnifiedBankData::getBankId, bank -> bank, (existing, replacement) -> existing));
        
        // 比较银行管理界面的每个银行
        for (BankInstitution managementBank : managementBanks) {
            if (managementBank.getBankId() != null) {
                UnifiedBankData loanSystemBank = loanSystemBankMap.get(managementBank.getBankId());
                differences.addAll(compareSingleBankData(managementBank, loanSystemBank));
            }
        }
        
        // 检查贷款系统中存在但管理界面中不存在的银行
        for (UnifiedBankData loanSystemBank : loanSystemBanks) {
            if (loanSystemBank.getBankId() != null) {
                boolean existsInManagement = managementBanks.stream()
                    .anyMatch(bank -> loanSystemBank.getBankId().equals(bank.getBankId()));
                
                if (!existsInManagement) {
                    differences.add(DataDifference.createMissingInManagement(
                        loanSystemBank.getBankId(), 
                        loanSystemBank.getBankName(), 
                        "bankRecord", 
                        "银行记录存在于贷款系统"
                    ));
                }
            }
        }
        
        return differences;
    }

    /**
     * 比较单个银行数据
     */
    private List<DataDifference> compareSingleBankData(BankInstitution managementBank, UnifiedBankData loanSystemBank)
    {
        List<DataDifference> differences = new ArrayList<>();
        
        if (managementBank == null && loanSystemBank == null) {
            return differences;
        }
        
        if (managementBank == null) {
            // 银行管理界面中缺失
            differences.add(DataDifference.createMissingInManagement(
                loanSystemBank.getBankId(), 
                loanSystemBank.getBankName(), 
                "bankRecord", 
                "银行记录存在于贷款系统"
            ));
            return differences;
        }
        
        if (loanSystemBank == null) {
            // 贷款系统中缺失
            differences.add(DataDifference.createMissingInLoanSystem(
                managementBank.getBankId(), 
                managementBank.getBankName(), 
                "bankRecord", 
                "银行记录存在于管理界面"
            ));
            return differences;
        }
        
        // 比较各个字段
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "bankName", managementBank.getBankName(), loanSystemBank.getBankName());
        
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "bankCode", managementBank.getBankCode(), loanSystemBank.getBankCode());
        
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "bankType", managementBank.getBankType(), loanSystemBank.getBankType());
        
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "status", managementBank.getStatus(), loanSystemBank.getStatus());
        
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "cooperationStatus", managementBank.getCooperationStatus(), loanSystemBank.getCooperationStatus());
        
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "baseInterestRate", managementBank.getBaseInterestRate(), loanSystemBank.getBaseInterestRate());
        
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "minLoanAmount", managementBank.getMinLoanAmountDecimal(), loanSystemBank.getMinLoanAmount());
        
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "maxLoanAmount", managementBank.getMaxLoanAmountDecimal(), loanSystemBank.getMaxLoanAmount());
        
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "minLoanTermMonths", managementBank.getMinLoanTermMonths(), loanSystemBank.getMinLoanTermMonths());
        
        compareField(differences, managementBank.getBankId(), managementBank.getBankName(), 
                    "maxLoanTermMonths", managementBank.getMaxLoanTermMonths(), loanSystemBank.getMaxLoanTermMonths());
        
        return differences;
    }

    /**
     * 比较单个字段
     */
    private void compareField(List<DataDifference> differences, Long bankId, String bankName, 
                             String fieldName, Object managementValue, Object loanSystemValue)
    {
        if (!Objects.equals(managementValue, loanSystemValue)) {
            // 特殊处理数值类型的比较
            if (managementValue instanceof BigDecimal && loanSystemValue instanceof BigDecimal) {
                BigDecimal mgmtDecimal = (BigDecimal) managementValue;
                BigDecimal loanDecimal = (BigDecimal) loanSystemValue;
                if (mgmtDecimal.compareTo(loanDecimal) != 0) {
                    differences.add(DataDifference.createValueDifference(bankId, bankName, fieldName, managementValue, loanSystemValue));
                }
            } else if (managementValue instanceof String && loanSystemValue instanceof String) {
                String mgmtStr = (String) managementValue;
                String loanStr = (String) loanSystemValue;
                if (!StringUtils.hasText(mgmtStr) && !StringUtils.hasText(loanStr)) {
                    // 都为空字符串，认为相等
                    return;
                }
                if (!Objects.equals(mgmtStr, loanStr)) {
                    differences.add(DataDifference.createValueDifference(bankId, bankName, fieldName, managementValue, loanSystemValue));
                }
            } else {
                differences.add(DataDifference.createValueDifference(bankId, bankName, fieldName, managementValue, loanSystemValue));
            }
        }
    }

    /**
     * 判断是否为关键字段
     */
    private boolean isCriticalField(String fieldName) {
        if (fieldName == null) {
            return false;
        }
        
        for (String criticalField : CRITICAL_FIELDS) {
            if (criticalField.equals(fieldName)) {
                return true;
            }
        }
        return false;
    }
}