package com.erp.systemtool.service;

import com.erp.systemtool.entity.SystemConfig;
import com.erp.systemtool.repository.SystemConfigRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * System Configuration Service
 * 
 * Manages system configuration with Redis caching.
 * Migrations from PHP SystemConfigController.
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SystemConfigService {

    private static final String CACHE_PREFIX = "sys_config:";
    private static final long CACHE_TTL_HOURS = 24;

    private final SystemConfigRepository configRepository;
    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * Get all configurations with caching
     */
    public Map<String, Map<String, String>> getAllConfigs(Integer tenantId) {
        String cacheKey = CACHE_PREFIX + tenantId + ":all";
        
        @SuppressWarnings("unchecked")
        Map<String, Map<String, String>> cached = (Map<String, Map<String, String>>) redisTemplate.opsForValue().get(cacheKey);
        if (cached != null) {
            return cached;
        }

        Map<String, Map<String, String>> result = new HashMap<>();
        List<SystemConfig> configs = configRepository.findAll();
        
        for (SystemConfig config : configs) {
            if (config.getTenantId().equals(tenantId)) {
                result.computeIfAbsent(config.getConfigGroup(), k -> new HashMap<>())
                      .put(config.getConfigKey(), config.getConfigValue());
            }
        }

        // Add default configs if not exists
        addDefaultConfigs(tenantId, result);

        redisTemplate.opsForValue().set(cacheKey, result, Duration.ofHours(CACHE_TTL_HOURS));
        return result;
    }

    /**
     * Get configurations for a specific group
     */
    public Map<String, String> getGroupConfigs(Integer tenantId, String group) {
        String cacheKey = CACHE_PREFIX + tenantId + ":" + group;
        
        @SuppressWarnings("unchecked")
        Map<String, String> cached = (Map<String, String>) redisTemplate.opsForValue().get(cacheKey);
        if (cached != null) {
            return cached;
        }

        List<SystemConfig> configs = configRepository.findByTenantIdAndConfigGroup(tenantId, group);
        Map<String, String> result = new HashMap<>();
        
        for (SystemConfig config : configs) {
            result.put(config.getConfigKey(), config.getConfigValue());
        }

        // Add defaults if empty
        if (result.isEmpty()) {
            addDefaultGroupConfigs(group, result);
        }

        redisTemplate.opsForValue().set(cacheKey, result, Duration.ofHours(CACHE_TTL_HOURS));
        return result;
    }

    /**
     * Update a configuration value
     */
    @Transactional
    public void updateConfig(Integer tenantId, String group, String key, Object value) {
        String strValue = value != null ? value.toString() : "";
        
        configRepository.findByTenantIdAndConfigGroupAndConfigKey(tenantId, group, key)
            .ifPresentOrElse(
                config -> {
                    config.setConfigValue(strValue);
                    configRepository.save(config);
                },
                () -> {
                    SystemConfig newConfig = SystemConfig.builder()
                        .tenantId(tenantId)
                        .configGroup(group)
                        .configKey(key)
                        .configValue(strValue)
                        .build();
                    configRepository.save(newConfig);
                }
            );

        // Clear cache
        clearCache(tenantId, group);
        log.info("Updated config: tenantId={}, group={}, key={}", tenantId, group, key);
    }

    /**
     * Batch update configurations
     */
    @Transactional
    public void batchUpdateConfigs(Integer tenantId, Map<String, Map<String, Object>> configs) {
        for (Map.Entry<String, Map<String, Object>> groupEntry : configs.entrySet()) {
            String group = groupEntry.getKey();
            for (Map.Entry<String, Object> itemEntry : groupEntry.getValue().entrySet()) {
                updateConfig(tenantId, group, itemEntry.getKey(), itemEntry.getValue());
            }
        }
    }

    /**
     * Get a single config value
     */
    public String getConfigValue(Integer tenantId, String group, String key, String defaultValue) {
        Map<String, String> groupConfigs = getGroupConfigs(tenantId, group);
        return groupConfigs.getOrDefault(key, defaultValue);
    }

    /**
     * Clear cache for a tenant's group
     */
    private void clearCache(Integer tenantId, String group) {
        redisTemplate.delete(CACHE_PREFIX + tenantId + ":" + group);
        redisTemplate.delete(CACHE_PREFIX + tenantId + ":all");
    }

    /**
     * Add default configurations
     */
    private void addDefaultConfigs(Integer tenantId, Map<String, Map<String, String>> result) {
        // Basic configs
        result.putIfAbsent("basic", new HashMap<>());
        addDefaultGroupConfigs("basic", result.get("basic"));
        
        // Order configs
        result.putIfAbsent("order", new HashMap<>());
        addDefaultGroupConfigs("order", result.get("order"));
        
        // Stock configs
        result.putIfAbsent("stock", new HashMap<>());
        addDefaultGroupConfigs("stock", result.get("stock"));
        
        // Express configs
        result.putIfAbsent("express", new HashMap<>());
        addDefaultGroupConfigs("express", result.get("express"));
        
        // Notify configs
        result.putIfAbsent("notify", new HashMap<>());
        addDefaultGroupConfigs("notify", result.get("notify"));
        
        // Security configs
        result.putIfAbsent("security", new HashMap<>());
        addDefaultGroupConfigs("security", result.get("security"));
        
        // Storage configs
        result.putIfAbsent("storage", new HashMap<>());
        addDefaultGroupConfigs("storage", result.get("storage"));
    }

    /**
     * Add default configs for a specific group
     */
    private void addDefaultGroupConfigs(String group, Map<String, String> configs) {
        switch (group) {
            case "basic":
                configs.putIfAbsent("site_name", "ERP SaaS 系统");
                configs.putIfAbsent("site_url", "https://erp.example.com");
                configs.putIfAbsent("site_logo", "/logo.png");
                configs.putIfAbsent("copyright", "© 2024 ERP SaaS");
                break;
            case "order":
                configs.putIfAbsent("auto_approve", "false");
                configs.putIfAbsent("approve_timeout_minutes", "30");
                configs.putIfAbsent("auto_reject_timeout_minutes", "60");
                configs.putIfAbsent("enable_stock_freeze", "true");
                configs.putIfAbsent("enable_audit_log", "true");
                break;
            case "stock":
                configs.putIfAbsent("enable_warning", "true");
                configs.putIfAbsent("default_warning_threshold", "10");
                configs.putIfAbsent("enable_negative_stock", "false");
                configs.putIfAbsent("auto_adjust_warning", "false");
                break;
            case "express":
                configs.putIfAbsent("default_express", "SF");
                configs.putIfAbsent("enable_electronic_waybill", "true");
                configs.putIfAbsent("waybill_cache_hours", "24");
                break;
            case "notify":
                configs.putIfAbsent("enable_dingtalk", "false");
                configs.putIfAbsent("dingtalk_webhook", "");
                configs.putIfAbsent("enable_sms", "false");
                configs.putIfAbsent("sms_provider", "aliyun");
                configs.putIfAbsent("notify_audit_timeout", "true");
                configs.putIfAbsent("notify_stock_warning", "true");
                break;
            case "security":
                configs.putIfAbsent("enable_mfa", "true");
                configs.putIfAbsent("session_timeout_minutes", "120");
                configs.putIfAbsent("max_login_attempts", "5");
                configs.putIfAbsent("password_min_length", "8");
                configs.putIfAbsent("enable_captcha", "true");
                break;
            case "storage":
                configs.putIfAbsent("driver", "local");
                configs.putIfAbsent("local_path", "/storage/uploads");
                configs.putIfAbsent("cos_bucket", "");
                configs.putIfAbsent("cos_region", "ap-guangzhou");
                configs.putIfAbsent("cos_secret_id", "");
                configs.putIfAbsent("cos_secret_key", "");
                break;
            default:
                break;
        }
    }
}
