package com.ruoyi.credit.config;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.credit.domain.ValidationRule;
import com.ruoyi.credit.mapper.ValidationRuleMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 验证规则配置管理类
 * 负责从配置文件加载验证规则，支持热更新和配置有效性验证
 * 
 * @author ruoyi
 * @date 2025-12-30
 */
@Component
public class ValidationRuleConfig {
    
    private static final Logger log = LoggerFactory.getLogger(ValidationRuleConfig.class);
    
    @Autowired
    private ValidationRuleMapper validationRuleMapper;
    
    @Autowired
    private ResourceLoader resourceLoader;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Autowired
    private ValidationRuleProperties properties;
    
    /**
     * 内存中的规则缓存
     */
    private final Map<String, ValidationRule> ruleCache = new ConcurrentHashMap<>();
    
    /**
     * 按类型分组的规则缓存
     */
    private final Map<String, List<ValidationRule>> rulesByType = new ConcurrentHashMap<>();
    
    /**
     * 按优先级排序的激活规则列表
     */
    private volatile List<ValidationRule> activeRulesSorted = new ArrayList<>();
    
    /**
     * 配置文件最后修改时间
     */
    private volatile long lastModified = 0L;
    
    /**
     * 热更新调度器
     */
    private ScheduledExecutorService hotReloadScheduler;
    
    /**
     * 文件监听服务
     */
    private WatchService watchService;
    
    /**
     * 配置文件监听线程
     */
    private Thread fileWatchThread;
    
    /**
     * 配置版本号
     */
    private volatile String configVersion = "1.0.0";
    
    /**
     * 初始化配置
     */
    @PostConstruct
    public void init() {
        log.info("初始化验证规则配置管理器...");
        
        // 加载初始配置
        loadValidationRules();
        
        // 启动热更新机制
        if (properties.getHotReload().isEnabled()) {
            startHotReload();
        }
        
        // 启动文件监听
        if (properties.getFileWatch().isEnabled()) {
            startFileWatch();
        }
        
        log.info("验证规则配置管理器初始化完成，当前加载规则数量: {}", ruleCache.size());
    }
    
    /**
     * 应用启动完成后加载数据库中的规则
     */
    @EventListener(ApplicationReadyEvent.class)
    public void onApplicationReady() {
        log.info("应用启动完成，开始同步数据库中的验证规则...");
        syncDatabaseRules();
    }
    
    /**
     * 从配置文件和数据库加载验证规则
     */
    public synchronized void loadValidationRules() {
        try {
            log.info("开始加载验证规则配置...");
            
            // 清空现有缓存
            ruleCache.clear();
            rulesByType.clear();
            
            // 从配置文件加载
            loadRulesFromConfigFile();
            
            // 从数据库加载
            loadRulesFromDatabase();
            
            // 重建缓存索引
            rebuildCacheIndexes();
            
            log.info("验证规则配置加载完成，总计加载规则: {}", ruleCache.size());
            
        } catch (Exception e) {
            log.error("加载验证规则配置失败", e);
            throw new RuntimeException("验证规则配置加载失败", e);
        }
    }
    
    /**
     * 从配置文件加载规则
     */
    private void loadRulesFromConfigFile() {
        try {
            Resource resource = resourceLoader.getResource(properties.getConfigFile());
            if (!resource.exists()) {
                log.warn("验证规则配置文件不存在: {}", properties.getConfigFile());
                return;
            }
            
            // 检查文件修改时间
            long currentModified = resource.lastModified();
            if (currentModified <= lastModified) {
                log.debug("配置文件未发生变化，跳过加载");
                return;
            }
            
            try (InputStream inputStream = resource.getInputStream()) {
                ValidationRuleConfigFile configFile = objectMapper.readValue(inputStream, ValidationRuleConfigFile.class);
                
                // 验证配置文件有效性
                validateConfigFile(configFile);
                
                // 更新配置版本
                if (StringUtils.hasText(configFile.getVersion())) {
                    this.configVersion = configFile.getVersion();
                }
                
                // 加载规则到缓存
                for (ValidationRule rule : configFile.getRules()) {
                    // 设置来源标识
                    rule.setCreatedBy("CONFIG_FILE");
                    ruleCache.put(rule.getRuleName(), rule);
                }
                
                lastModified = currentModified;
                log.info("从配置文件加载规则数量: {}, 版本: {}", configFile.getRules().size(), configVersion);
                
            }
        } catch (IOException e) {
            log.error("读取验证规则配置文件失败: {}", properties.getConfigFile(), e);
        }
    }
    
    /**
     * 从数据库加载规则
     */
    private void loadRulesFromDatabase() {
        try {
            List<ValidationRule> dbRules = validationRuleMapper.selectValidationRuleList(new ValidationRule());
            for (ValidationRule rule : dbRules) {
                // 数据库中的规则优先级更高，会覆盖配置文件中的同名规则
                ruleCache.put(rule.getRuleName(), rule);
            }
            log.info("从数据库加载规则数量: {}", dbRules.size());
        } catch (Exception e) {
            log.error("从数据库加载验证规则失败", e);
        }
    }
    
    /**
     * 同步数据库规则（将配置文件中的规则同步到数据库）
     */
    private void syncDatabaseRules() {
        try {
            List<ValidationRule> configRules = ruleCache.values().stream()
                .filter(rule -> "CONFIG_FILE".equals(rule.getCreatedBy()))
                .collect(Collectors.toList());
            
            for (ValidationRule configRule : configRules) {
                ValidationRule existingRule = validationRuleMapper.selectValidationRuleByRuleName(configRule.getRuleName());
                if (existingRule == null) {
                    // 新规则，插入到数据库
                    configRule.setCreatedBy("SYSTEM_SYNC");
                    validationRuleMapper.insertValidationRule(configRule);
                    log.info("同步新规则到数据库: {}", configRule.getRuleName());
                }
            }
        } catch (Exception e) {
            log.error("同步数据库规则失败", e);
        }
    }
    
    /**
     * 重建缓存索引
     */
    private void rebuildCacheIndexes() {
        // 按类型分组
        rulesByType.clear();
        for (ValidationRule rule : ruleCache.values()) {
            rulesByType.computeIfAbsent(rule.getRuleType(), k -> new ArrayList<>()).add(rule);
        }
        
        // 构建按优先级排序的激活规则列表
        activeRulesSorted = ruleCache.values().stream()
            .filter(ValidationRule::isActive)
            .sorted(Comparator.comparing(ValidationRule::getPriority))
            .collect(Collectors.toList());
        
        log.debug("重建缓存索引完成，激活规则数量: {}", activeRulesSorted.size());
    }
    
    /**
     * 验证配置文件有效性
     */
    private void validateConfigFile(ValidationRuleConfigFile configFile) {
        if (configFile == null) {
            throw new IllegalArgumentException("配置文件内容为空");
        }
        
        if (configFile.getRules() == null || configFile.getRules().isEmpty()) {
            log.warn("配置文件中没有定义验证规则");
            return;
        }
        
        Set<String> ruleNames = new HashSet<>();
        Set<Integer> priorities = new HashSet<>();
        
        for (ValidationRule rule : configFile.getRules()) {
            // 验证必填字段
            if (!StringUtils.hasText(rule.getRuleName())) {
                throw new IllegalArgumentException("规则名称不能为空");
            }
            
            if (!StringUtils.hasText(rule.getRuleType())) {
                throw new IllegalArgumentException("规则类型不能为空: " + rule.getRuleName());
            }
            
            if (!StringUtils.hasText(rule.getRuleExpression())) {
                throw new IllegalArgumentException("规则表达式不能为空: " + rule.getRuleName());
            }
            
            if (rule.getPriority() == null || rule.getPriority() <= 0) {
                throw new IllegalArgumentException("规则优先级必须大于0: " + rule.getRuleName());
            }
            
            // 检查规则名称唯一性
            if (!ruleNames.add(rule.getRuleName())) {
                throw new IllegalArgumentException("规则名称重复: " + rule.getRuleName());
            }
            
            // 检查优先级唯一性
            if (!priorities.add(rule.getPriority())) {
                throw new IllegalArgumentException("规则优先级重复: " + rule.getPriority());
            }
            
            // 验证规则状态
            if (!StringUtils.hasText(rule.getRuleStatus())) {
                rule.setRuleStatus(ValidationRule.STATUS_ACTIVE);
            } else if (!isValidRuleStatus(rule.getRuleStatus())) {
                throw new IllegalArgumentException("无效的规则状态: " + rule.getRuleStatus());
            }
            
            // 验证规则类型
            if (!isValidRuleType(rule.getRuleType())) {
                throw new IllegalArgumentException("无效的规则类型: " + rule.getRuleType());
            }
        }
        
        log.info("配置文件验证通过，规则数量: {}", configFile.getRules().size());
    }
    
    /**
     * 检查规则状态是否有效
     */
    private boolean isValidRuleStatus(String status) {
        return ValidationRule.STATUS_ACTIVE.equals(status) ||
               ValidationRule.STATUS_INACTIVE.equals(status) ||
               ValidationRule.STATUS_DRAFT.equals(status) ||
               ValidationRule.STATUS_DEPRECATED.equals(status);
    }
    
    /**
     * 检查规则类型是否有效
     */
    private boolean isValidRuleType(String type) {
        return ValidationRule.TYPE_CREDIT_EXISTENCE.equals(type) ||
               ValidationRule.TYPE_CREDIT_VALIDITY.equals(type) ||
               ValidationRule.TYPE_CONTRACT_MATCH.equals(type) ||
               ValidationRule.TYPE_AMOUNT_CONSISTENCY.equals(type) ||
               ValidationRule.TYPE_DATE_CONSISTENCY.equals(type) ||
               ValidationRule.TYPE_STATUS_VALIDATION.equals(type);
    }
    
    /**
     * 启动热更新机制
     */
    private void startHotReload() {
        hotReloadScheduler = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r, "ValidationRuleConfig-HotReload");
            t.setDaemon(true);
            return t;
        });
        
        hotReloadScheduler.scheduleWithFixedDelay(() -> {
            try {
                log.debug("执行验证规则热更新检查...");
                loadValidationRules();
            } catch (Exception e) {
                log.error("热更新检查失败", e);
            }
        }, properties.getHotReload().getInterval(), properties.getHotReload().getInterval(), TimeUnit.SECONDS);
        
        log.info("验证规则热更新机制已启动，检查间隔: {} 秒", properties.getHotReload().getInterval());
    }
    
    /**
     * 启动文件监听
     */
    private void startFileWatch() {
        try {
            watchService = FileSystems.getDefault().newWatchService();
            
            fileWatchThread = new Thread(() -> {
                try {
                    Resource resource = resourceLoader.getResource(properties.getConfigFile());
                    if (resource.getFile() != null) {
                        Path configPath = resource.getFile().toPath();
                        Path parentDir = configPath.getParent();
                        
                        parentDir.register(watchService, 
                            StandardWatchEventKinds.ENTRY_MODIFY,
                            StandardWatchEventKinds.ENTRY_CREATE);
                        
                        log.info("开始监听配置文件变化: {}", configPath);
                        
                        while (!Thread.currentThread().isInterrupted()) {
                            WatchKey key = watchService.take();
                            
                            for (WatchEvent<?> event : key.pollEvents()) {
                                Path changed = (Path) event.context();
                                if (changed.equals(configPath.getFileName())) {
                                    log.info("检测到配置文件变化，触发重新加载: {}", changed);
                                    loadValidationRules();
                                }
                            }
                            
                            key.reset();
                        }
                    }
                } catch (Exception e) {
                    log.error("文件监听失败", e);
                }
            }, "ValidationRuleConfig-FileWatch");
            
            fileWatchThread.setDaemon(true);
            fileWatchThread.start();
            
        } catch (Exception e) {
            log.error("启动文件监听失败", e);
        }
    }
    
    /**
     * 获取所有激活的验证规则（按优先级排序）
     */
    public List<ValidationRule> getActiveRules() {
        return new ArrayList<>(activeRulesSorted);
    }
    
    /**
     * 根据规则名称获取规则
     */
    public ValidationRule getRuleByName(String ruleName) {
        return ruleCache.get(ruleName);
    }
    
    /**
     * 根据规则类型获取规则列表
     */
    public List<ValidationRule> getRulesByType(String ruleType) {
        return rulesByType.getOrDefault(ruleType, Collections.emptyList());
    }
    
    /**
     * 获取所有规则
     */
    public Collection<ValidationRule> getAllRules() {
        return new ArrayList<>(ruleCache.values());
    }
    
    /**
     * 获取配置版本
     */
    public String getConfigVersion() {
        return configVersion;
    }
    
    /**
     * 手动触发配置重新加载
     */
    public void reloadConfig() {
        log.info("手动触发验证规则配置重新加载...");
        loadValidationRules();
    }
    
    /**
     * 销毁资源
     */
    public void destroy() {
        if (hotReloadScheduler != null && !hotReloadScheduler.isShutdown()) {
            hotReloadScheduler.shutdown();
        }
        
        if (fileWatchThread != null && !fileWatchThread.isInterrupted()) {
            fileWatchThread.interrupt();
        }
        
        if (watchService != null) {
            try {
                watchService.close();
            } catch (IOException e) {
                log.error("关闭文件监听服务失败", e);
            }
        }
        
        log.info("验证规则配置管理器资源已释放");
    }
    
    /**
     * 配置文件结构类
     */
    public static class ValidationRuleConfigFile {
        private String version;
        private String description;
        private List<ValidationRule> rules;
        
        public String getVersion() {
            return version;
        }
        
        public void setVersion(String version) {
            this.version = version;
        }
        
        public String getDescription() {
            return description;
        }
        
        public void setDescription(String description) {
            this.description = description;
        }
        
        public List<ValidationRule> getRules() {
            return rules;
        }
        
        public void setRules(List<ValidationRule> rules) {
            this.rules = rules;
        }
    }
}