package com.agent.management.rag.bridge;

import com.agent.management.config.RagAiBridgeProperties;
import com.agent.management.model.entity.AiModel;
import com.agent.management.service.AiModelService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 管理 RAG AI Bridge Python 子进程的生命周期。
 * 仅在 rag.ai-bridge.enabled=true 时激活。
 *
 * LLM 配置从 spring.ai.openai.* 读取，通过环境变量注入子进程
 * （OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL / LLM_TEMPERATURE），
 * 实现 application.yml 作为大模型配置的单一来源。
 */
@Slf4j
@Component
@ConditionalOnProperty(name = "rag.ai-bridge.enabled", havingValue = "true")
public class RagAiBridgeProcessManager {

    private final RagAiBridgeProperties properties;
    private final RagAiBridgeClient client;
    private final AiModelService aiModelService;
    /** spring.ai.openai.* 中的 LLM 配置，通过环境变量传给 Bridge 子进程 */
    private final String llmBaseUrl;
    private final String llmApiKey;
    private final String llmModel;
    private final String llmTemperature;

    private Process process;
    private final AtomicBoolean starting = new AtomicBoolean(false);
    private ScheduledExecutorService healthScheduler;
    /** 显式关闭标志，用于区分关闭流程与运行期异常 */
    private volatile boolean stopped = false;

    public RagAiBridgeProcessManager(
            RagAiBridgeProperties properties,
            RagAiBridgeClient client,
            AiModelService aiModelService,
            @Value("${spring.ai.openai.base-url:}") String llmBaseUrl,
            @Value("${spring.ai.openai.api-key:}") String llmApiKey,
            @Value("${spring.ai.openai.chat.options.model:}") String llmModel,
            @Value("${spring.ai.openai.chat.options.temperature:0.3}") String llmTemperature) {
        this.properties = properties;
        this.client = client;
        this.aiModelService = aiModelService;
        this.llmBaseUrl = llmBaseUrl;
        this.llmApiKey = llmApiKey;
        this.llmModel = llmModel;
        this.llmTemperature = llmTemperature;
    }

    @PostConstruct
    public void start() {
        log.info("[RagAiBridge] 启动子进程...");
        if (!starting.compareAndSet(false, true)) return;

        try {
            if (client.health()) {
                log.info("[RagAiBridge] existing healthy instance detected; reusing it");
                starting.set(false);
                startHealthCheck();
                return;
            }
            String scriptPath = resolveScriptPath();
            String pythonPath = properties.getPythonPath();
            int port = properties.getPort();
            LlmConfig llm = resolveLlmConfig();

            // server.py 不支持 --port/--host 命令行参数，全部通过环境变量传
            ProcessBuilder pb = new ProcessBuilder(pythonPath, scriptPath);
            pb.redirectErrorStream(true);

            Map<String, String> env = pb.environment();
            env.put("PYTHONUNBUFFERED", "1");
            // 强制 Python 子进程 stdin/stdout/stderr 使用 UTF-8（Windows 默认 cp936 会导致中文乱码）
            env.put("PYTHONIOENCODING", "utf-8");
            env.put("PYTHONUTF8", "1");
            env.put("RAG_AI_BRIDGE_HOST", properties.getHost());
            env.put("RAG_AI_BRIDGE_PORT", String.valueOf(port));
            env.put("LLM_TIMEOUT", String.valueOf(properties.getTimeout().toSeconds()));

            // LLM 配置注入：从 spring.ai.openai.* 读取，实现 application.yml 单一配置源
            if (llm.baseUrl() != null && !llm.baseUrl().isBlank()) {
                env.put("OPENAI_BASE_URL", llm.baseUrl());
            }
            if (llm.apiKey() != null && !llm.apiKey().isBlank()) {
                env.put("OPENAI_API_KEY", llm.apiKey());
            }
            if (llm.model() != null && !llm.model().isBlank()) {
                env.put("OPENAI_MODEL", llm.model());
            }
            if (llm.temperature() != null && !llm.temperature().isBlank()) {
                env.put("LLM_TEMPERATURE", llm.temperature());
            }

            // 日志中不输出 base_url / model / api_key 详情，避免敏感信息泄露
            log.info("[RagAiBridge] 使用{}模型配置，BASE_URL={}，MODEL={}，API_KEY={}，TEMPERATURE={}",
                    llm.source(),
                    (llm.baseUrl() != null && !llm.baseUrl().isBlank() ? "已设置" : "未设置"),
                    (llm.model() != null && !llm.model().isBlank() ? "已设置" : "未设置"),
                    (llm.apiKey() != null && !llm.apiKey().isBlank() ? "已设置" : "未设置"),
                    llm.temperature());

            // 设置工作目录为项目根目录
            File projectRoot = new File(System.getProperty("user.dir"));
            pb.directory(projectRoot);

            process = pb.start();

            // 异步读取子进程输出（避免缓冲区满导致阻塞）
            Thread outputReader = new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        log.debug("[RagAiBridge] {}", line);
                    }
                } catch (IOException e) {
                    if (!stopped) {
                        log.warn("[RagAiBridge] 输出流关闭: {}", e.getMessage());
                    }
                }
            }, "rag-ai-bridge-output");
            outputReader.setDaemon(true);
            outputReader.start();

            // 等待健康检查通过
            long deadline = System.currentTimeMillis() + properties.getStartupTimeout() * 1000L;
            while (System.currentTimeMillis() < deadline) {
                Thread.sleep(1000);
                if (client.health()) {
                    log.info("[RagAiBridge] 子进程启动成功，端口: {}", port);
                    starting.set(false);
                    startHealthCheck();
                    return;
                }
            }

            log.error("[RagAiBridge] 子进程启动超时（{}秒）", properties.getStartupTimeout());
            starting.set(false);

        } catch (Exception e) {
            log.error("[RagAiBridge] 子进程启动失败: {}", e.getMessage(), e);
            starting.set(false);
        }
    }

    @PreDestroy
    public void stop() {
        stopped = true;
        if (healthScheduler != null) {
            healthScheduler.shutdownNow();
        }
        if (process != null && process.isAlive()) {
            log.info("[RagAiBridge] 停止子进程...");
            process.destroy();
            try {
                if (!process.waitFor(5, TimeUnit.SECONDS)) {
                    process.destroyForcibly();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                process.destroyForcibly();
            }
            log.info("[RagAiBridge] 子进程已停止");
        }
    }

    /**
     * 检查 Bridge 是否就绪
     */
    public boolean isReady() {
        if (starting.get()) return false;
        return client.health();
    }

    private void startHealthCheck() {
        int interval = properties.getHealthCheckInterval();
        if (interval <= 0) return;
        if (healthScheduler != null && !healthScheduler.isShutdown()) return;

        healthScheduler = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r, "rag-ai-bridge-health-check");
            t.setDaemon(true);
            return t;
        });

        healthScheduler.scheduleAtFixedRate(() -> {
            if (stopped) return;
            if ((process == null || !process.isAlive()) && !client.health()) {
                log.warn("[RagAiBridge] 子进程已退出，尝试重启...");
                start();
            }
        }, interval, interval, TimeUnit.SECONDS);
    }

    private String resolveScriptPath() {
        String path = properties.getScriptPath();
        File file = new File(path);
        if (!file.isAbsolute()) {
            file = new File(System.getProperty("user.dir"), path);
        }
        if (!file.exists()) {
            throw new IllegalStateException("RAG AI Bridge 脚本不存在: " + file.getAbsolutePath());
        }
        return file.getAbsolutePath();
    }

    private LlmConfig resolveLlmConfig() {
        if (hasText(llmApiKey) && !isPlaceholder(llmApiKey) && hasText(llmModel)) {
            return new LlmConfig(llmBaseUrl, llmApiKey, llmModel, llmTemperature, "application.yml");
        }
        for (AiModel model : aiModelService.listModels()) {
            if (hasText(model.getBaseUrl()) && hasText(model.getApiKey()) && hasText(model.getModelName())) {
                String temperature = model.getTemperature() == null
                        ? llmTemperature : String.valueOf(model.getTemperature());
                return new LlmConfig(model.getBaseUrl(), model.getApiKey(), model.getModelName(),
                        temperature, "模型管理");
            }
        }
        throw new IllegalStateException("RAG AI Bridge 未找到可用的大模型配置");
    }

    private static boolean hasText(String value) {
        return value != null && !value.isBlank();
    }

    private static boolean isPlaceholder(String value) {
        return value != null && value.toLowerCase().contains("placeholder");
    }

    private record LlmConfig(String baseUrl, String apiKey, String model,
                             String temperature, String source) {}
}
