package com.ycwl.basic.integration.render.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
import com.ycwl.basic.integration.render.client.RenderWorkerV2Client;
import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest;
import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 渲染工作器配置集成服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RenderWorkerConfigIntegrationService {

    private final RenderWorkerV2Client renderWorkerConfigV2Client;
    private final IntegrationFallbackService fallbackService;
    
    private static final String SERVICE_NAME = "zt-render-worker";

    /**
     * 获取工作器所有配置（带降级，使用TypeReference保留泛型信息）
     */
    public List<RenderWorkerConfigV2DTO> getWorkerConfigs(Long workerId) {
        log.debug("获取渲染工作器配置列表, workerId: {}", workerId);
        return fallbackService.executeWithFallback(
            SERVICE_NAME,
            "worker:configs:" + workerId,
            () -> {
                CommonResponse<List<RenderWorkerConfigV2DTO>> response =
                    renderWorkerConfigV2Client.getWorkerConfigs(workerId);
                List<RenderWorkerConfigV2DTO> configs = handleResponse(response, "获取渲染工作器配置列表失败");
                return configs != null ? configs : Collections.emptyList();
            },
            new TypeReference<List<RenderWorkerConfigV2DTO>>() {}
        );
    }

    /**
     * 根据配置键获取特定配置（带降级）
     */
    public RenderWorkerConfigV2DTO getWorkerConfigByKey(Long workerId, String configKey) {
        log.debug("根据配置键获取渲染工作器配置, workerId: {}, configKey: {}", workerId, configKey);
        return fallbackService.executeWithFallback(
            SERVICE_NAME,
            "worker:config:" + workerId + ":" + configKey,
            () -> {
                CommonResponse<RenderWorkerConfigV2DTO> response = 
                    renderWorkerConfigV2Client.getWorkerConfigByKey(workerId, configKey);
                return handleResponse(response, "根据配置键获取渲染工作器配置失败");
            },
            RenderWorkerConfigV2DTO.class
        );
    }

    /**
     * 获取工作器平铺配置（带降级）
     */
    public Map<String, Object> getWorkerFlatConfig(Long workerId) {
        log.debug("获取渲染工作器平铺配置, workerId: {}", workerId);
        return fallbackService.executeWithFallback(
            SERVICE_NAME,
            "worker:flat:config:" + workerId,
            () -> {
                List<RenderWorkerConfigV2DTO> configs = getWorkerConfigsInternal(workerId);
                return flattenConfigs(configs);
            },
            new TypeReference<Map<String, Object>>() {}
        );
    }

    /**
     * 创建配置（直接调用，不降级）
     */
    public RenderWorkerConfigV2DTO createWorkerConfig(Long workerId, RenderWorkerConfigV2DTO config) {
        log.debug("创建渲染工作器配置, workerId: {}, configKey: {}", workerId, config.getConfigKey());
        CommonResponse<RenderWorkerConfigV2DTO> response = 
            renderWorkerConfigV2Client.createWorkerConfig(workerId, config);
        RenderWorkerConfigV2DTO result = handleResponse(response, "创建渲染工作器配置失败");
        // 清理配置相关缓存
        clearWorkerConfigCache(workerId, config.getConfigKey());
        return result;
    }

    /**
     * 更新配置（直接调用，不降级）
     */
    public void updateWorkerConfig(Long workerId, Long configId, Map<String, Object> updates) {
        log.debug("更新渲染工作器配置, workerId: {}, configId: {}", workerId, configId);
        CommonResponse<Void> response = 
            renderWorkerConfigV2Client.updateWorkerConfig(workerId, configId, updates);
        handleVoidResponse(response, "更新渲染工作器配置失败");
        // 清理所有配置缓存（无法确定具体key）
        clearAllWorkerConfigCache(workerId);
    }

    /**
     * 删除配置（直接调用，不降级）
     */
    public void deleteWorkerConfig(Long workerId, Long configId) {
        log.debug("删除渲染工作器配置, workerId: {}, configId: {}", workerId, configId);
        CommonResponse<Void> response = 
            renderWorkerConfigV2Client.deleteWorkerConfig(workerId, configId);
        handleVoidResponse(response, "删除渲染工作器配置失败");
        // 清理所有配置缓存（无法确定具体key）
        clearAllWorkerConfigCache(workerId);
    }

    /**
     * 批量更新配置（直接调用，不降级）
     */
    public void batchUpdateWorkerConfigs(Long workerId, BatchRenderWorkerConfigRequest request) {
        log.debug("批量更新渲染工作器配置, workerId: {}, configCount: {}", 
                 workerId, request.getConfigs() != null ? request.getConfigs().size() : 0);
        CommonResponse<Void> response = 
            renderWorkerConfigV2Client.batchUpdateWorkerConfigs(workerId, request);
        handleVoidResponse(response, "批量更新渲染工作器配置失败");
        // 清理所有配置缓存
        clearAllWorkerConfigCache(workerId);
    }

    /**
     * 批量平铺更新配置（直接调用，不降级）
     */
    public void batchFlatUpdateWorkerConfigs(Long workerId, Map<String, Object> flatConfigs) {
        log.debug("批量平铺更新渲染工作器配置, workerId: {}, configCount: {}", 
                 workerId, flatConfigs.size());
        
        BatchRenderWorkerConfigRequest request = new BatchRenderWorkerConfigRequest();
        List<RenderWorkerConfigV2DTO> configs = flatConfigs.entrySet().stream()
            .map(entry -> {
                RenderWorkerConfigV2DTO config = new RenderWorkerConfigV2DTO();
                config.setConfigKey(entry.getKey());
                config.setConfigValue(String.valueOf(entry.getValue()));
                config.setConfigType(determineConfigType(entry.getValue()));
                config.setIsActive(1);
                return config;
            })
            .toList();
        
        request.setConfigs(configs);
        batchUpdateWorkerConfigs(workerId, request);
        // 缓存清理已在 batchUpdateWorkerConfigs 中处理
    }

    /**
     * 清理指定配置的缓存
     */
    private void clearWorkerConfigCache(Long workerId, String configKey) {
        fallbackService.clearFallbackCache(SERVICE_NAME, "worker:configs:" + workerId);
        fallbackService.clearFallbackCache(SERVICE_NAME, "worker:flat:config:" + workerId);
        if (configKey != null) {
            fallbackService.clearFallbackCache(SERVICE_NAME, "worker:config:" + workerId + ":" + configKey);
        }
    }

    /**
     * 清理工作器所有配置缓存
     */
    private void clearAllWorkerConfigCache(Long workerId) {
        fallbackService.clearFallbackCache(SERVICE_NAME, "worker:configs:" + workerId);
        fallbackService.clearFallbackCache(SERVICE_NAME, "worker:flat:config:" + workerId);
    }

    /**
     * 创建批量配置构建器
     */
    public BatchConfigBuilder createBatchConfigBuilder() {
        return new BatchConfigBuilder();
    }

    /**
     * 内部获取配置方法（不使用降级）
     */
    private List<RenderWorkerConfigV2DTO> getWorkerConfigsInternal(Long workerId) {
        CommonResponse<List<RenderWorkerConfigV2DTO>> response = 
            renderWorkerConfigV2Client.getWorkerConfigs(workerId);
        List<RenderWorkerConfigV2DTO> configs = handleResponse(response, "获取渲染工作器配置列表失败");
        return configs != null ? configs : Collections.emptyList();
    }

    /**
     * 将配置列表转换为平铺Map
     */
    private Map<String, Object> flattenConfigs(List<RenderWorkerConfigV2DTO> configs) {
        Map<String, Object> flatConfig = new HashMap<>();
        for (RenderWorkerConfigV2DTO config : configs) {
            if (config.getIsActive() == 1) {
                Object value = convertConfigValue(config.getConfigValue(), config.getConfigType());
                flatConfig.put(config.getConfigKey(), value);
            }
        }
        return flatConfig;
    }

    /**
     * 根据配置类型转换配置值
     */
    private Object convertConfigValue(String configValue, String configType) {
        if (configValue == null) return null;
        
        return switch (configType) {
            case "int" -> Integer.parseInt(configValue);
            case "float" -> Double.parseDouble(configValue);
            case "bool" -> Boolean.parseBoolean(configValue);
            case "json" -> configValue; // 保持JSON字符串格式
            default -> configValue; // string类型或其他
        };
    }

    /**
     * 自动判断配置类型
     */
    private String determineConfigType(Object value) {
        if (value instanceof Integer) return "int";
        if (value instanceof Double || value instanceof Float) return "float";
        if (value instanceof Boolean) return "bool";
        return "string";
    }

    /**
     * 处理通用响应
     */
    private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
        if (response == null || !response.getSuccess()) {
            String msg = response != null && response.getMessage() != null ? 
                        response.getMessage() : errorMessage;
            Integer code = response != null ? response.getCode() : 5000;
            throw new IntegrationException(code, msg, SERVICE_NAME);
        }
        return response.getData();
    }

    /**
     * 处理空响应
     */
    private void handleVoidResponse(CommonResponse<Void> response, String errorMessage) {
        if (response == null || !response.getSuccess()) {
            String msg = response != null && response.getMessage() != null ? 
                        response.getMessage() : errorMessage;
            Integer code = response != null ? response.getCode() : 5000;
            throw new IntegrationException(code, msg, SERVICE_NAME);
        }
    }

    /**
     * 批量配置构建器
     */
    public static class BatchConfigBuilder {
        private final List<RenderWorkerConfigV2DTO> configs = new java.util.ArrayList<>();

        /**
         * 添加配置项
         */
        public BatchConfigBuilder addConfig(String key, String value) {
            return addConfig(key, value, "string", null);
        }

        /**
         * 添加配置项（指定类型）
         */
        public BatchConfigBuilder addConfig(String key, String value, String type) {
            return addConfig(key, value, type, null);
        }

        /**
         * 添加配置项（完整）
         */
        public BatchConfigBuilder addConfig(String key, String value, String type, String description) {
            RenderWorkerConfigV2DTO config = new RenderWorkerConfigV2DTO();
            config.setConfigKey(key);
            config.setConfigValue(value);
            config.setConfigType(type);
            config.setDescription(description);
            config.setIsActive(1);
            configs.add(config);
            return this;
        }

        /**
         * 添加渲染配置
         */
        public BatchConfigBuilder addRenderConfig(String quality, String format, String resolution) {
            return addConfig("render_quality", quality, "string", "渲染质量")
                   .addConfig("render_format", format, "string", "渲染格式")
                   .addConfig("render_resolution", resolution, "string", "渲染分辨率");
        }

        /**
         * 添加性能配置
         */
        public BatchConfigBuilder addPerformanceConfig(Integer maxTasks, Integer timeout) {
            return addConfig("max_concurrent_tasks", String.valueOf(maxTasks), "int", "最大并发任务数")
                   .addConfig("task_timeout", String.valueOf(timeout), "int", "任务超时时间(秒)");
        }

        /**
         * 构建批量配置请求
         */
        public BatchRenderWorkerConfigRequest build() {
            BatchRenderWorkerConfigRequest request = new BatchRenderWorkerConfigRequest();
            request.setConfigs(configs);
            return request;
        }
    }
}