package org.dromara.ai.error;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.ai.domain.dto.AiChatRequest;
import org.dromara.ai.domain.dto.AiChatResponse;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * AI错误处理和故障恢复服务
 * 提供统一的错误处理、重试机制和故障恢复功能
 *
 * @author pengles
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AiErrorHandler {

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

    // 错误统计
    private final Map<String, ErrorStatistics> errorStats = new ConcurrentHashMap<>();

    // 熔断器状态
    private final Map<String, CircuitBreakerState> circuitBreakers = new ConcurrentHashMap<>();

    // 重试配置
    private final Map<String, RetryConfig> retryConfigs = new ConcurrentHashMap<>();

    /**
     * 错误类型枚举
     */
    public enum ErrorType {
        NETWORK_ERROR,          // 网络错误
        TIMEOUT_ERROR,          // 超时错误
        RATE_LIMIT_ERROR,       // 速率限制错误
        QUOTA_EXCEEDED_ERROR,   // 配额超限错误
        AUTHENTICATION_ERROR,   // 认证错误
        AUTHORIZATION_ERROR,    // 授权错误
        VALIDATION_ERROR,       // 验证错误
        SERVICE_UNAVAILABLE,    // 服务不可用
        INTERNAL_ERROR,         // 内部错误
        UNKNOWN_ERROR           // 未知错误
    }

    /**
     * 错误严重级别
     */
    public enum ErrorSeverity {
        LOW,        // 低级别
        MEDIUM,     // 中级别
        HIGH,       // 高级别
        CRITICAL    // 严重级别
    }

    /**
     * 熔断器状态
     */
    public enum CircuitBreakerStatus {
        CLOSED,     // 关闭状态（正常）
        OPEN,       // 开启状态（熔断）
        HALF_OPEN   // 半开状态（试探）
    }

    /**
     * 错误信息类
     */
    public static class AiError {
        private String id;
        private ErrorType type;
        private ErrorSeverity severity;
        private String message;
        private String details;
        private String provider;
        private String model;
        private String userId;
        private LocalDateTime occurTime;
        private Map<String, Object> context;
        private Throwable cause;

        // Getters and Setters
        public String getId() {
            return id;
        }

        public AiError setId(String id) {
            this.id = id;
            return this;
        }

        public ErrorType getType() {
            return type;
        }

        public AiError setType(ErrorType type) {
            this.type = type;
            return this;
        }

        public ErrorSeverity getSeverity() {
            return severity;
        }

        public AiError setSeverity(ErrorSeverity severity) {
            this.severity = severity;
            return this;
        }

        public String getMessage() {
            return message;
        }

        public AiError setMessage(String message) {
            this.message = message;
            return this;
        }

        public String getDetails() {
            return details;
        }

        public AiError setDetails(String details) {
            this.details = details;
            return this;
        }

        public String getProvider() {
            return provider;
        }

        public AiError setProvider(String provider) {
            this.provider = provider;
            return this;
        }

        public String getModel() {
            return model;
        }

        public AiError setModel(String model) {
            this.model = model;
            return this;
        }

        public String getUserId() {
            return userId;
        }

        public AiError setUserId(String userId) {
            this.userId = userId;
            return this;
        }

        public LocalDateTime getOccurTime() {
            return occurTime;
        }

        public AiError setOccurTime(LocalDateTime occurTime) {
            this.occurTime = occurTime;
            return this;
        }

        public Map<String, Object> getContext() {
            return context;
        }

        public AiError setContext(Map<String, Object> context) {
            this.context = context;
            return this;
        }

        public Throwable getCause() {
            return cause;
        }

        public AiError setCause(Throwable cause) {
            this.cause = cause;
            return this;
        }
    }

    /**
     * 错误统计类
     */
    public static class ErrorStatistics {
        private String key;
        private long totalErrors;
        private long networkErrors;
        private long timeoutErrors;
        private long rateLimitErrors;
        private long quotaErrors;
        private long authErrors;
        private long validationErrors;
        private long serviceUnavailableErrors;
        private long internalErrors;
        private long unknownErrors;
        private LocalDateTime lastErrorTime;
        private LocalDateTime firstErrorTime;
        private double errorRate;

        public ErrorStatistics(String key) {
            this.key = key;
            this.firstErrorTime = LocalDateTime.now();
        }

        public void incrementError(ErrorType type) {
            totalErrors++;
            lastErrorTime = LocalDateTime.now();

            switch (type) {
                case NETWORK_ERROR -> networkErrors++;
                case TIMEOUT_ERROR -> timeoutErrors++;
                case RATE_LIMIT_ERROR -> rateLimitErrors++;
                case QUOTA_EXCEEDED_ERROR -> quotaErrors++;
                case AUTHENTICATION_ERROR, AUTHORIZATION_ERROR -> authErrors++;
                case VALIDATION_ERROR -> validationErrors++;
                case SERVICE_UNAVAILABLE -> serviceUnavailableErrors++;
                case INTERNAL_ERROR -> internalErrors++;
                default -> unknownErrors++;
            }
        }

        // Getters
        public String getKey() {
            return key;
        }

        public long getTotalErrors() {
            return totalErrors;
        }

        public long getNetworkErrors() {
            return networkErrors;
        }

        public long getTimeoutErrors() {
            return timeoutErrors;
        }

        public long getRateLimitErrors() {
            return rateLimitErrors;
        }

        public long getQuotaErrors() {
            return quotaErrors;
        }

        public long getAuthErrors() {
            return authErrors;
        }

        public long getValidationErrors() {
            return validationErrors;
        }

        public long getServiceUnavailableErrors() {
            return serviceUnavailableErrors;
        }

        public long getInternalErrors() {
            return internalErrors;
        }

        public long getUnknownErrors() {
            return unknownErrors;
        }

        public LocalDateTime getLastErrorTime() {
            return lastErrorTime;
        }

        public LocalDateTime getFirstErrorTime() {
            return firstErrorTime;
        }

        public double getErrorRate() {
            return errorRate;
        }

        public void setErrorRate(double errorRate) {
            this.errorRate = errorRate;
        }
    }

    /**
     * 熔断器状态类
     */
    public static class CircuitBreakerState {
        private String key;
        private CircuitBreakerStatus status;
        private long failureCount;
        private long successCount;
        private LocalDateTime lastFailureTime;
        private LocalDateTime lastSuccessTime;
        private LocalDateTime nextRetryTime;
        private int failureThreshold;
        private int successThreshold;
        private long timeoutMs;

        public CircuitBreakerState(String key) {
            this.key = key;
            this.status = CircuitBreakerStatus.CLOSED;
            this.failureThreshold = 5;
            this.successThreshold = 3;
            this.timeoutMs = 60000; // 1分钟
        }

        public void recordSuccess() {
            successCount++;
            lastSuccessTime = LocalDateTime.now();

            if (status == CircuitBreakerStatus.HALF_OPEN && successCount >= successThreshold) {
                status = CircuitBreakerStatus.CLOSED;
                failureCount = 0;
                successCount = 0;
            }
        }

        public void recordFailure() {
            failureCount++;
            lastFailureTime = LocalDateTime.now();

            if (status == CircuitBreakerStatus.CLOSED && failureCount >= failureThreshold) {
                status = CircuitBreakerStatus.OPEN;
                nextRetryTime = LocalDateTime.now().plusNanos(timeoutMs * 1_000_000);
            } else if (status == CircuitBreakerStatus.HALF_OPEN) {
                status = CircuitBreakerStatus.OPEN;
                nextRetryTime = LocalDateTime.now().plusNanos(timeoutMs * 1_000_000);
                successCount = 0;
            }
        }

        public boolean canExecute() {
            if (status == CircuitBreakerStatus.CLOSED) {
                return true;
            } else if (status == CircuitBreakerStatus.OPEN) {
                if (LocalDateTime.now().isAfter(nextRetryTime)) {
                    status = CircuitBreakerStatus.HALF_OPEN;
                    return true;
                }
                return false;
            } else { // HALF_OPEN
                return true;
            }
        }

        // Getters
        public String getKey() {
            return key;
        }

        public CircuitBreakerStatus getStatus() {
            return status;
        }

        public long getFailureCount() {
            return failureCount;
        }

        public long getSuccessCount() {
            return successCount;
        }

        public LocalDateTime getLastFailureTime() {
            return lastFailureTime;
        }

        public LocalDateTime getLastSuccessTime() {
            return lastSuccessTime;
        }

        public LocalDateTime getNextRetryTime() {
            return nextRetryTime;
        }
    }

    /**
     * 重试配置类
     */
    public static class RetryConfig {
        private int maxAttempts;
        private long initialDelayMs;
        private long maxDelayMs;
        private double backoffMultiplier;
        private boolean exponentialBackoff;

        public RetryConfig() {
            this.maxAttempts = 3;
            this.initialDelayMs = 1000;
            this.maxDelayMs = 30000;
            this.backoffMultiplier = 2.0;
            this.exponentialBackoff = true;
        }

        // Getters and Setters
        public int getMaxAttempts() {
            return maxAttempts;
        }

        public RetryConfig setMaxAttempts(int maxAttempts) {
            this.maxAttempts = maxAttempts;
            return this;
        }

        public long getInitialDelayMs() {
            return initialDelayMs;
        }

        public RetryConfig setInitialDelayMs(long initialDelayMs) {
            this.initialDelayMs = initialDelayMs;
            return this;
        }

        public long getMaxDelayMs() {
            return maxDelayMs;
        }

        public RetryConfig setMaxDelayMs(long maxDelayMs) {
            this.maxDelayMs = maxDelayMs;
            return this;
        }

        public double getBackoffMultiplier() {
            return backoffMultiplier;
        }

        public RetryConfig setBackoffMultiplier(double backoffMultiplier) {
            this.backoffMultiplier = backoffMultiplier;
            return this;
        }

        public boolean isExponentialBackoff() {
            return exponentialBackoff;
        }

        public RetryConfig setExponentialBackoff(boolean exponentialBackoff) {
            this.exponentialBackoff = exponentialBackoff;
            return this;
        }
    }

    /**
     * 执行带错误处理的操作
     *
     * @param key       操作标识
     * @param operation 操作函数
     * @param request   请求对象
     * @return 响应结果
     */
    public AiChatResponse executeWithErrorHandling(String key,
                                                   Function<AiChatRequest, AiChatResponse> operation,
                                                   AiChatRequest request) {
        CircuitBreakerState circuitBreaker = getOrCreateCircuitBreaker(key);

        // 检查熔断器状态
        if (!circuitBreaker.canExecute()) {
            AiError error = new AiError()
                    .setType(ErrorType.SERVICE_UNAVAILABLE)
                    .setSeverity(ErrorSeverity.HIGH)
                    .setMessage("服务熔断中，暂时不可用")
                    .setProvider(key)
                    .setUserId(request.getUserId())
                    .setOccurTime(LocalDateTime.now());

            recordError(key, error);
            return createErrorResponse(error, request);
        }

        RetryConfig retryConfig = getOrCreateRetryConfig(key);

        for (int attempt = 1; attempt <= retryConfig.getMaxAttempts(); attempt++) {
            try {
                AiChatResponse response = operation.apply(request);

                if (response.getSuccess() != null && response.getSuccess()) {
                    circuitBreaker.recordSuccess();
                    return response;
                } else {
                    // 业务错误
                    AiError error = createErrorFromResponse(response, request);
                    recordError(key, error);

                    if (attempt == retryConfig.getMaxAttempts() || !isRetryableError(error.getType())) {
                        circuitBreaker.recordFailure();
                        return response;
                    }
                }

            } catch (Exception e) {
                AiError error = createErrorFromException(e, key, request);
                recordError(key, error);

                if (attempt == retryConfig.getMaxAttempts() || !isRetryableError(error.getType())) {
                    circuitBreaker.recordFailure();
                    return createErrorResponse(error, request);
                }

                // 等待重试
                if (attempt < retryConfig.getMaxAttempts()) {
                    try {
                        long delay = calculateRetryDelay(retryConfig, attempt);
                        Thread.sleep(delay);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }

        // 所有重试都失败
        AiError error = new AiError()
                .setType(ErrorType.INTERNAL_ERROR)
                .setSeverity(ErrorSeverity.HIGH)
                .setMessage("所有重试尝试都失败")
                .setProvider(key)
                .setUserId(request.getUserId())
                .setOccurTime(LocalDateTime.now());

        circuitBreaker.recordFailure();
        return createErrorResponse(error, request);
    }

    /**
     * 记录错误
     *
     * @param key   错误标识
     * @param error 错误信息
     */
    public void recordError(String key, AiError error) {
        ErrorStatistics stats = errorStats.computeIfAbsent(key, ErrorStatistics::new);
        stats.incrementError(error.getType());

        log.error("AI错误记录 - Key: {}, Type: {}, Severity: {}, Message: {}",
                key, error.getType(), error.getSeverity(), error.getMessage());

        // 根据错误严重级别进行不同处理
        switch (error.getSeverity()) {
            case CRITICAL -> handleCriticalError(error);
            case HIGH -> handleHighSeverityError(error);
            case MEDIUM -> handleMediumSeverityError(error);
            case LOW -> handleLowSeverityError(error);
        }
    }

    /**
     * 获取错误统计
     *
     * @param key 统计标识
     * @return 错误统计
     */
    public ErrorStatistics getErrorStatistics(String key) {
        return errorStats.get(key);
    }

    /**
     * 获取所有错误统计
     *
     * @return 错误统计映射
     */
    public Map<String, ErrorStatistics> getAllErrorStatistics() {
        return new ConcurrentHashMap<>(errorStats);
    }

    /**
     * 获取熔断器状态
     *
     * @param key 熔断器标识
     * @return 熔断器状态
     */
    public CircuitBreakerState getCircuitBreakerState(String key) {
        return circuitBreakers.get(key);
    }

    /**
     * 重置熔断器
     *
     * @param key 熔断器标识
     */
    public void resetCircuitBreaker(String key) {
        CircuitBreakerState state = circuitBreakers.get(key);
        if (state != null) {
            state.status = CircuitBreakerStatus.CLOSED;
            state.failureCount = 0;
            state.successCount = 0;
            log.info("熔断器已重置: {}", key);
        }
    }

    /**
     * 设置重试配置
     *
     * @param key    配置标识
     * @param config 重试配置
     */
    public void setRetryConfig(String key, RetryConfig config) {
        retryConfigs.put(key, config);
    }

    /**
     * 清理错误统计
     */
    public void clearErrorStatistics() {
        errorStats.clear();
        log.info("错误统计已清理");
    }

    /**
     * 获取或创建熔断器
     */
    private CircuitBreakerState getOrCreateCircuitBreaker(String key) {
        return circuitBreakers.computeIfAbsent(key, CircuitBreakerState::new);
    }

    /**
     * 获取或创建重试配置
     */
    private RetryConfig getOrCreateRetryConfig(String key) {
        return retryConfigs.computeIfAbsent(key, k -> new RetryConfig());
    }

    /**
     * 判断是否为可重试错误
     */
    private boolean isRetryableError(ErrorType errorType) {
        return switch (errorType) {
            case NETWORK_ERROR, TIMEOUT_ERROR, SERVICE_UNAVAILABLE, RATE_LIMIT_ERROR -> true;
            case AUTHENTICATION_ERROR, AUTHORIZATION_ERROR, VALIDATION_ERROR, QUOTA_EXCEEDED_ERROR -> false;
            default -> true;
        };
    }

    /**
     * 计算重试延迟
     */
    private long calculateRetryDelay(RetryConfig config, int attempt) {
        if (!config.isExponentialBackoff()) {
            return config.getInitialDelayMs();
        }

        long delay = (long) (config.getInitialDelayMs() * Math.pow(config.getBackoffMultiplier(), attempt - 1));
        return Math.min(delay, config.getMaxDelayMs());
    }

    /**
     * 从异常创建错误对象
     */
    private AiError createErrorFromException(Exception e, String provider, AiChatRequest request) {
        ErrorType type = classifyException(e);
        ErrorSeverity severity = determineSeverity(type);

        return new AiError()
                .setId(java.util.UUID.randomUUID().toString())
                .setType(type)
                .setSeverity(severity)
                .setMessage(e.getMessage())
                .setDetails(getStackTrace(e))
                .setProvider(provider)
                .setModel(request.getModel())
                .setUserId(request.getUserId())
                .setOccurTime(LocalDateTime.now())
                .setCause(e);
    }

    /**
     * 从响应创建错误对象
     */
    private AiError createErrorFromResponse(AiChatResponse response, AiChatRequest request) {
        ErrorType type = classifyResponseError(response);
        ErrorSeverity severity = determineSeverity(type);

        return new AiError()
                .setId(java.util.UUID.randomUUID().toString())
                .setType(type)
                .setSeverity(severity)
                .setMessage(response.getError())
                .setDetails(response.getErrorCode())
                .setProvider(response.getProvider())
                .setModel(response.getModel())
                .setUserId(request.getUserId())
                .setOccurTime(LocalDateTime.now());
    }

    /**
     * 分类异常类型
     */
    private ErrorType classifyException(Exception e) {
        String message = e.getMessage();
        if (message == null) {
            return ErrorType.UNKNOWN_ERROR;
        }

        message = message.toLowerCase();

        if (message.contains("timeout") || message.contains("timed out")) {
            return ErrorType.TIMEOUT_ERROR;
        } else if (message.contains("network") || message.contains("connection")) {
            return ErrorType.NETWORK_ERROR;
        } else if (message.contains("rate limit") || message.contains("too many requests")) {
            return ErrorType.RATE_LIMIT_ERROR;
        } else if (message.contains("quota") || message.contains("limit exceeded")) {
            return ErrorType.QUOTA_EXCEEDED_ERROR;
        } else if (message.contains("unauthorized") || message.contains("authentication")) {
            return ErrorType.AUTHENTICATION_ERROR;
        } else if (message.contains("forbidden") || message.contains("access denied")) {
            return ErrorType.AUTHORIZATION_ERROR;
        } else if (message.contains("validation") || message.contains("invalid")) {
            return ErrorType.VALIDATION_ERROR;
        } else if (message.contains("service unavailable") || message.contains("server error")) {
            return ErrorType.SERVICE_UNAVAILABLE;
        } else {
            return ErrorType.INTERNAL_ERROR;
        }
    }

    /**
     * 分类响应错误类型
     */
    private ErrorType classifyResponseError(AiChatResponse response) {
        String errorCode = response.getErrorCode();
        String errorMessage = response.getError();

        if (errorCode != null) {
            return switch (errorCode.toUpperCase()) {
                case "TIMEOUT", "TIMEOUT_ERROR" -> ErrorType.TIMEOUT_ERROR;
                case "RATE_LIMIT", "RATE_LIMIT_ERROR" -> ErrorType.RATE_LIMIT_ERROR;
                case "QUOTA_EXCEEDED" -> ErrorType.QUOTA_EXCEEDED_ERROR;
                case "AUTH_ERROR", "AUTHENTICATION_ERROR" -> ErrorType.AUTHENTICATION_ERROR;
                case "AUTHORIZATION_ERROR" -> ErrorType.AUTHORIZATION_ERROR;
                case "VALIDATION_ERROR" -> ErrorType.VALIDATION_ERROR;
                case "SERVICE_UNAVAILABLE" -> ErrorType.SERVICE_UNAVAILABLE;
                case "NETWORK_ERROR" -> ErrorType.NETWORK_ERROR;
                default -> ErrorType.INTERNAL_ERROR;
            };
        }

        if (errorMessage != null) {
            return classifyException(new RuntimeException(errorMessage));
        }

        return ErrorType.UNKNOWN_ERROR;
    }

    /**
     * 确定错误严重级别
     */
    private ErrorSeverity determineSeverity(ErrorType errorType) {
        return switch (errorType) {
            case AUTHENTICATION_ERROR, AUTHORIZATION_ERROR -> ErrorSeverity.CRITICAL;
            case SERVICE_UNAVAILABLE, QUOTA_EXCEEDED_ERROR -> ErrorSeverity.HIGH;
            case NETWORK_ERROR, TIMEOUT_ERROR, RATE_LIMIT_ERROR -> ErrorSeverity.MEDIUM;
            case VALIDATION_ERROR -> ErrorSeverity.LOW;
            default -> ErrorSeverity.MEDIUM;
        };
    }

    /**
     * 创建错误响应
     */
    private AiChatResponse createErrorResponse(AiError error, AiChatRequest request) {
        return new AiChatResponse()
                .setSuccess(false)
                .setError(error.getMessage())
                .setErrorCode(error.getType().name())
                .setModel(request.getModel())
                .setProvider(error.getProvider())
                .setCreateTime(LocalDateTime.now());
    }

    /**
     * 获取异常堆栈信息
     */
    private String getStackTrace(Exception e) {
        java.io.StringWriter sw = new java.io.StringWriter();
        java.io.PrintWriter pw = new java.io.PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
    }

    /**
     * 处理严重错误
     */
    private void handleCriticalError(AiError error) {
        log.error("严重错误发生: {}", error.getMessage());
        // 可以发送告警、通知等
    }

    /**
     * 处理高级别错误
     */
    private void handleHighSeverityError(AiError error) {
        log.warn("高级别错误发生: {}", error.getMessage());
        // 可以记录到特殊日志、发送通知等
    }

    /**
     * 处理中级别错误
     */
    private void handleMediumSeverityError(AiError error) {
        log.warn("中级别错误发生: {}", error.getMessage());
    }

    /**
     * 处理低级别错误
     */
    private void handleLowSeverityError(AiError error) {
        log.debug("低级别错误发生: {}", error.getMessage());
    }

    /**
     * 销毁资源
     */
    public void destroy() {
        if (scheduler != null && !scheduler.isShutdown()) {
            scheduler.shutdown();
            try {
                if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                    scheduler.shutdownNow();
                }
            } catch (InterruptedException e) {
                scheduler.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        log.info("AI错误处理器已销毁");
    }
}