package org.dromara.ai.provider;

import lombok.extern.slf4j.Slf4j;
import org.dromara.ai.domain.dto.AiChatRequest;
import org.dromara.ai.domain.dto.AiChatResponse;
import org.dromara.ai.domain.dto.AiModelInfo;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

/**
 * AI服务提供商抽象基类
 * 提供通用功能实现和统计信息管理
 *
 * @author pengles
 */
@Slf4j
public abstract class AbstractAiProvider implements AiProvider {

    /**
     * 提供商配置
     */
    protected Map<String, Object> configuration = new ConcurrentHashMap<>();

    /**
     * 是否已初始化
     */
    protected final AtomicBoolean initialized = new AtomicBoolean(false);

    /**
     * 是否可用
     */
    protected final AtomicBoolean available = new AtomicBoolean(false);

    /**
     * 统计信息
     */
    protected final Statistics statistics = new Statistics();

    /**
     * 初始化时间
     */
    protected LocalDateTime initTime;

    @Override
    public void initialize(Map<String, Object> config) {
        try {
            log.info("初始化AI提供商: {}", getProviderName());

            if (config != null) {
                this.configuration.putAll(config);
            }

            // 执行具体的初始化逻辑
            doInitialize();

            this.initialized.set(true);
            this.available.set(true);
            this.initTime = LocalDateTime.now();

            log.info("AI提供商初始化成功: {}", getProviderName());

        } catch (Exception e) {
            log.error("AI提供商初始化失败: {}", getProviderName(), e);
            this.initialized.set(false);
            this.available.set(false);
            throw new RuntimeException("AI提供商初始化失败: " + e.getMessage(), e);
        }
    }

    @Override
    public void destroy() {
        try {
            log.info("销毁AI提供商: {}", getProviderName());

            // 执行具体的销毁逻辑
            doDestroy();

            this.initialized.set(false);
            this.available.set(false);

            log.info("AI提供商销毁成功: {}", getProviderName());

        } catch (Exception e) {
            log.error("AI提供商销毁失败: {}", getProviderName(), e);
        }
    }

    @Override
    public boolean isAvailable() {
        return initialized.get() && available.get();
    }

    @Override
    public AiChatResponse chat(AiChatRequest request) {
        checkAvailable();

        long startTime = System.currentTimeMillis();
        statistics.incrementRequestCount();

        try {
            AiChatResponse response = doChat(request);

            long responseTime = System.currentTimeMillis() - startTime;
            response.setResponseTime(responseTime);
            response.setProvider(getProviderName());
            response.setSuccess(true);
            response.setCreateTime(LocalDateTime.now());

            statistics.incrementSuccessCount();
            statistics.addResponseTime(responseTime);

            if (response.getUsage() != null) {
                statistics.addTokenUsage(
                        response.getUsage().getPromptTokens(),
                        response.getUsage().getCompletionTokens()
                );
            }

            return response;

        } catch (Exception e) {
            long responseTime = System.currentTimeMillis() - startTime;
            statistics.incrementErrorCount();
            statistics.addResponseTime(responseTime);

            log.error("AI聊天请求失败: {}", getProviderName(), e);

            return new AiChatResponse()
                    .setSuccess(false)
                    .setError(e.getMessage())
                    .setErrorCode("CHAT_ERROR")
                    .setProvider(getProviderName())
                    .setResponseTime(responseTime)
                    .setCreateTime(LocalDateTime.now());
        }
    }

    @Override
    public CompletableFuture<AiChatResponse> chatAsync(AiChatRequest request) {
        return CompletableFuture.supplyAsync(() -> chat(request));
    }

    @Override
    public void chatStream(AiChatRequest request, StreamCallback callback) {
        checkAvailable();

        long startTime = System.currentTimeMillis();
        statistics.incrementRequestCount();

        try {
            doChatStream(request, new StreamCallback() {
                @Override
                public void onChunk(String chunk) {
                    callback.onChunk(chunk);
                }

                @Override
                public void onComplete(AiChatResponse response) {
                    long responseTime = System.currentTimeMillis() - startTime;
                    response.setResponseTime(responseTime);
                    response.setProvider(getProviderName());
                    response.setSuccess(true);
                    response.setCreateTime(LocalDateTime.now());

                    statistics.incrementSuccessCount();
                    statistics.addResponseTime(responseTime);

                    if (response.getUsage() != null) {
                        statistics.addTokenUsage(
                                response.getUsage().getPromptTokens(),
                                response.getUsage().getCompletionTokens()
                        );
                    }

                    callback.onComplete(response);
                }

                @Override
                public void onError(Throwable error) {
                    long responseTime = System.currentTimeMillis() - startTime;
                    statistics.incrementErrorCount();
                    statistics.addResponseTime(responseTime);

                    log.error("AI流式聊天请求失败: {}", getProviderName(), error);
                    callback.onError(error);
                }
            });

        } catch (Exception e) {
            long responseTime = System.currentTimeMillis() - startTime;
            statistics.incrementErrorCount();
            statistics.addResponseTime(responseTime);

            log.error("AI流式聊天请求失败: {}", getProviderName(), e);
            callback.onError(e);
        }
    }

    @Override
    public boolean isModelSupported(String modelName) {
        return getSupportedModels().stream()
                .anyMatch(model -> model.getId().equals(modelName) || model.getName().equals(modelName));
    }

    @Override
    public AiModelInfo getModelInfo(String modelName) {
        return getSupportedModels().stream()
                .filter(model -> model.getId().equals(modelName) || model.getName().equals(modelName))
                .findFirst()
                .orElse(null);
    }

    @Override
    public Map<String, Object> getConfiguration() {
        return new ConcurrentHashMap<>(configuration);
    }

    @Override
    public void updateConfiguration(Map<String, Object> config) {
        if (config != null) {
            this.configuration.putAll(config);
            // 触发配置更新
            onConfigurationUpdated();
        }
    }

    @Override
    public Map<String, Object> getStatistics() {
        Map<String, Object> stats = new ConcurrentHashMap<>();
        stats.put("providerName", getProviderName());
        stats.put("providerType", getProviderType().getCode());
        stats.put("version", getVersion());
        stats.put("available", isAvailable());
        stats.put("initialized", initialized.get());
        stats.put("initTime", initTime);
        stats.put("requestCount", statistics.getRequestCount());
        stats.put("successCount", statistics.getSuccessCount());
        stats.put("errorCount", statistics.getErrorCount());
        stats.put("averageResponseTime", statistics.getAverageResponseTime());
        stats.put("totalPromptTokens", statistics.getTotalPromptTokens());
        stats.put("totalCompletionTokens", statistics.getTotalCompletionTokens());
        stats.put("totalTokens", statistics.getTotalTokens());
        return stats;
    }

    @Override
    public void resetStatistics() {
        statistics.reset();
        log.info("重置AI提供商统计信息: {}", getProviderName());
    }

    /**
     * 检查提供商是否可用
     */
    protected void checkAvailable() {
        if (!isAvailable()) {
            throw new IllegalStateException("AI提供商不可用: " + getProviderName());
        }
    }

    /**
     * 执行具体的初始化逻辑
     */
    protected abstract void doInitialize();

    /**
     * 执行具体的销毁逻辑
     */
    protected abstract void doDestroy();

    /**
     * 执行具体的聊天逻辑
     */
    protected abstract AiChatResponse doChat(AiChatRequest request);

    /**
     * 执行具体的流式聊天逻辑
     */
    protected abstract void doChatStream(AiChatRequest request, StreamCallback callback);

    /**
     * 配置更新回调
     */
    protected void onConfigurationUpdated() {
        // 子类可以重写此方法来处理配置更新
    }

    /**
     * 统计信息类
     */
    protected static class Statistics {
        private final AtomicLong requestCount = new AtomicLong(0);
        private final AtomicLong successCount = new AtomicLong(0);
        private final AtomicLong errorCount = new AtomicLong(0);
        private final AtomicLong totalResponseTime = new AtomicLong(0);
        private final AtomicLong totalPromptTokens = new AtomicLong(0);
        private final AtomicLong totalCompletionTokens = new AtomicLong(0);

        public void incrementRequestCount() {
            requestCount.incrementAndGet();
        }

        public void incrementSuccessCount() {
            successCount.incrementAndGet();
        }

        public void incrementErrorCount() {
            errorCount.incrementAndGet();
        }

        public void addResponseTime(long responseTime) {
            totalResponseTime.addAndGet(responseTime);
        }

        public void addTokenUsage(Integer promptTokens, Integer completionTokens) {
            if (promptTokens != null) {
                totalPromptTokens.addAndGet(promptTokens);
            }
            if (completionTokens != null) {
                totalCompletionTokens.addAndGet(completionTokens);
            }
        }

        public long getRequestCount() {
            return requestCount.get();
        }

        public long getSuccessCount() {
            return successCount.get();
        }

        public long getErrorCount() {
            return errorCount.get();
        }

        public double getAverageResponseTime() {
            long requests = requestCount.get();
            return requests > 0 ? (double) totalResponseTime.get() / requests : 0.0;
        }

        public long getTotalPromptTokens() {
            return totalPromptTokens.get();
        }

        public long getTotalCompletionTokens() {
            return totalCompletionTokens.get();
        }

        public long getTotalTokens() {
            return totalPromptTokens.get() + totalCompletionTokens.get();
        }

        public void reset() {
            requestCount.set(0);
            successCount.set(0);
            errorCount.set(0);
            totalResponseTime.set(0);
            totalPromptTokens.set(0);
            totalCompletionTokens.set(0);
        }
    }
}