package cn.novalon.gym.manage.gateway.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 配置热更新服务
 * 
 * 文件定义：实现配置的动态更新和管理
 * 涉及业务：配置刷新、配置监听、配置版本管理
 * 
 * 核心功能：
 * 1. 配置热更新
 * 2. 配置版本管理
 * 3. 配置变更监听
 * 4. 配置回滚
 * 
 * @author 张翔
 * @date 2026-03-26
 */
@Service
@RefreshScope
public class ConfigRefreshService {

    private static final Logger logger = LoggerFactory.getLogger(ConfigRefreshService.class);

    private final ContextRefresher contextRefresher;
    private final Environment environment;
    private final ConfigurableEnvironment configurableEnvironment;

    private final Map<String, String> configHistory = new ConcurrentHashMap<>();
    private final Map<String, Long> configUpdateTime = new ConcurrentHashMap<>();
    private final Map<String, ConfigChangeListener> listeners = new ConcurrentHashMap<>();

    private long currentVersion = System.currentTimeMillis();

    public ConfigRefreshService(
            ContextRefresher contextRefresher,
            Environment environment,
            ConfigurableEnvironment configurableEnvironment) {
        this.contextRefresher = contextRefresher;
        this.environment = environment;
        this.configurableEnvironment = configurableEnvironment;

        logger.info("ConfigRefreshService initialized");
    }

    public void refreshConfig() {
        logger.info("Refreshing configuration");
        
        try {
            Set<String> refreshedKeys = contextRefresher.refresh();
            
            if (!refreshedKeys.isEmpty()) {
                currentVersion = System.currentTimeMillis();
                logger.info("Configuration refreshed. Version: {}, Updated keys: {}", 
                        currentVersion, refreshedKeys);
                
                notifyListeners(refreshedKeys);
            } else {
                logger.info("No configuration changes detected");
            }
        } catch (Exception e) {
            logger.error("Failed to refresh configuration", e);
        }
    }

    public void updateConfig(String key, String value) {
        if (key == null || key.isEmpty()) {
            logger.warn("Config key is null or empty");
            return;
        }

        String oldValue = environment.getProperty(key);
        
        logger.info("Updating config - Key: {}, Old Value: {}, New Value: {}", 
                key, oldValue, value);

        configHistory.put(key, oldValue);
        configUpdateTime.put(key, System.currentTimeMillis());

        try {
            Map<String, Object> newConfig = new HashMap<>();
            newConfig.put(key, value);

            MapPropertySource propertySource = new MapPropertySource(
                    "dynamicConfig", 
                    newConfig);

            configurableEnvironment.getPropertySources()
                    .addFirst(propertySource);

            logger.info("Config updated successfully: {}", key);
            
            notifyListeners(Set.of(key));
        } catch (Exception e) {
            logger.error("Failed to update config: {}", key, e);
        }
    }

    public void batchUpdateConfig(Map<String, String> configs) {
        if (configs == null || configs.isEmpty()) {
            logger.warn("No configs to update");
            return;
        }

        logger.info("Batch updating {} configs", configs.size());

        configs.forEach((key, value) -> {
            String oldValue = environment.getProperty(key);
            configHistory.put(key, oldValue);
            configUpdateTime.put(key, System.currentTimeMillis());
        });

        try {
            Map<String, Object> newConfigs = new HashMap<>(configs);

            MapPropertySource propertySource = new MapPropertySource(
                    "batchDynamicConfig", 
                    newConfigs);

            configurableEnvironment.getPropertySources()
                    .addFirst(propertySource);

            logger.info("Batch config update completed");
            
            notifyListeners(configs.keySet());
        } catch (Exception e) {
            logger.error("Failed to batch update configs", e);
        }
    }

    public String getConfig(String key) {
        if (key == null || key.isEmpty()) {
            logger.warn("Config key is null or empty");
            return null;
        }

        return environment.getProperty(key);
    }

    public String getConfigWithDefault(String key, String defaultValue) {
        return environment.getProperty(key, defaultValue);
    }

    public void rollbackConfig(String key) {
        if (key == null || key.isEmpty()) {
            logger.warn("Config key is null or empty");
            return;
        }

        String oldValue = configHistory.get(key);
        
        if (oldValue != null) {
            logger.info("Rolling back config: {} to value: {}", key, oldValue);
            updateConfig(key, oldValue);
        } else {
            logger.warn("No history found for config: {}", key);
        }
    }

    public void registerListener(String key, ConfigChangeListener listener) {
        if (key == null || key.isEmpty() || listener == null) {
            logger.warn("Invalid listener registration");
            return;
        }

        listeners.put(key, listener);
        logger.info("Registered listener for config: {}", key);
    }

    public void unregisterListener(String key) {
        if (key != null && !key.isEmpty()) {
            listeners.remove(key);
            logger.info("Unregistered listener for config: {}", key);
        }
    }

    private void notifyListeners(Set<String> changedKeys) {
        changedKeys.forEach(key -> {
            ConfigChangeListener listener = listeners.get(key);
            if (listener != null) {
                try {
                    String newValue = environment.getProperty(key);
                    listener.onConfigChange(key, newValue);
                    logger.debug("Notified listener for config: {}", key);
                } catch (Exception e) {
                    logger.error("Failed to notify listener for config: {}", key, e);
                }
            }
        });
    }

    public long getCurrentVersion() {
        return currentVersion;
    }

    public Map<String, String> getConfigHistory() {
        return new HashMap<>(configHistory);
    }

    public Map<String, Long> getConfigUpdateTime() {
        return new HashMap<>(configUpdateTime);
    }

    public void clearHistory() {
        logger.info("Clearing config history");
        configHistory.clear();
        configUpdateTime.clear();
    }

    @FunctionalInterface
    public interface ConfigChangeListener {
        void onConfigChange(String key, String newValue);
    }
}
