package com.agent.management.engine.hermes;

import com.agent.management.config.HermesProperties;
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.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.net.HttpURLConnection;
import java.net.URI;
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;

/**
 * 管理 Hermes Bridge Python 子进程的生命周期。
 * 仅在 hermes.enabled=true 时激活。
 */
@Slf4j
@Component
@ConditionalOnProperty(name = "hermes.enabled", havingValue = "true")
public class HermesProcessManager {

    private final HermesProperties properties;
    /** spring.ai.openai.* 中的 LLM 配置，将通过环境变量传递给 Bridge 子进程 */
    private final String llmBaseUrl;
    private final String llmApiKey;
    private final String llmModel;

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

    public HermesProcessManager(
            HermesProperties properties,
            @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) {
        this.properties = properties;
        this.llmBaseUrl = llmBaseUrl;
        this.llmApiKey = llmApiKey;
        this.llmModel = llmModel;
    }

    @PostConstruct
    public void start() {
        if (!properties.isEnabled()) {
            return;
        }

        log.info("[Hermes] 启动 Bridge 子进程...");
        starting.set(true);

        try {
            String scriptPath = resolveScriptPath();
            String pythonPath = properties.getBridge().getPythonPath();
            int port = properties.getBridge().getPort();
            // 固定 HERMES_HOME：进程生命周期内不变，保证 hermes-agent 的
            // SKILLS_DIR 模块级常量（首次 import 时冻结）始终指向该目录
            String hermesHome = properties.getBridge().getResolvedHome().toString();

            ProcessBuilder pb = new ProcessBuilder(
                    pythonPath, scriptPath,
                    "--port", String.valueOf(port),
                    "--host", "127.0.0.1",
                    "--hermes-home", hermesHome
            );
            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");

            // H5: 优先使用 hermes.bridge.llm-api-key（独立 Key），为空时回退到 spring.ai.openai.api-key
            String effectiveApiKey = properties.getBridge().getLlmApiKey();
            boolean useIsolatedKey = effectiveApiKey != null && !effectiveApiKey.isBlank();
            if (!useIsolatedKey) {
                effectiveApiKey = llmApiKey;
            }
            if (llmBaseUrl != null && !llmBaseUrl.isBlank()) {
                env.put("HERMES_BRIDGE_BASE_URL", llmBaseUrl);
            }
            if (effectiveApiKey != null && !effectiveApiKey.isBlank()) {
                env.put("HERMES_BRIDGE_API_KEY", effectiveApiKey);
            }
            if (llmModel != null && !llmModel.isBlank()) {
                env.put("HERMES_BRIDGE_MODEL", llmModel);
            }

            // M5: 生成并注入访问令牌，Bridge 端会校验 X-Bridge-Token 头
            // 启动时若未配置则自动生成一次性 token（每次重启进程都会变化）
            String authToken = properties.getBridge().getAuthToken();
            if (authToken == null || authToken.isBlank()) {
                authToken = generateRandomToken();
                log.warn("[Hermes] hermes.bridge.auth-token 未配置，已生成临时 token（重启后变化，建议显式配置）");
                // 回写到 properties，让 HermesBridgeClient 能取得同一个 token 发送请求
                properties.getBridge().setAuthToken(authToken);
            }
            env.put("HERMES_BRIDGE_AUTH_TOKEN", authToken);

            // 日志中不输出 base_url / model / api_key 详情，仅提示是否就绪，避免敏感信息泄露
            log.info("[Hermes] Bridge 环境变量已注入: BASE_URL={}, MODEL={}, API_KEY={} (isolated={}), AUTH_TOKEN=已设置",
                    (llmBaseUrl != null && !llmBaseUrl.isBlank() ? "已设置" : "未设置"),
                    (llmModel != null && !llmModel.isBlank() ? "已设置" : "未设置"),
                    (effectiveApiKey != null && !effectiveApiKey.isBlank() ? "已设置" : "未设置"),
                    useIsolatedKey);

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

            process = pb.start();

            // 异步读取子进程输出（避免缓冲区满导致阻塞）
            // 显式指定 UTF-8：Process.inputReader() 默认使用平台 charset（Windows 为 cp936），
            // 与 Python 输出（UTF-8）不匹配会导致中文乱码
            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("[Hermes-Bridge] {}", line);
                    }
                } catch (IOException e) {
                    if (!stopped) {
                        log.warn("[Hermes-Bridge] 输出流关闭: {}", e.getMessage());
                    }
                }
            }, "hermes-bridge-output");
            outputReader.setDaemon(true);
            outputReader.start();

            // 等待健康检查通过
            long deadline = System.currentTimeMillis() + properties.getBridge().getStartupTimeout() * 1000L;
            String healthUrl = "http://127.0.0.1:" + port + "/health";

            while (System.currentTimeMillis() < deadline) {
                Thread.sleep(1000);
                if (checkHealth(healthUrl)) {
                    log.info("[Hermes] Bridge 启动成功，端口: {}", port);
                    starting.set(false);
                    startHealthCheck();
                    return;
                }
            }

            log.error("[Hermes] Bridge 启动超时（{}秒）", properties.getBridge().getStartupTimeout());
            starting.set(false);

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

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

    /**
     * 检查 Bridge 是否就绪
     */
    public boolean isReady() {
        if (starting.get()) return false;
        if (process == null || !process.isAlive()) return false;
        String url = "http://127.0.0.1:" + properties.getBridge().getPort() + "/health";
        return checkHealth(url);
    }

    private boolean checkHealth(String url) {
        try {
            HttpURLConnection conn = (HttpURLConnection) URI.create(url).toURL().openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(2000);
            conn.setReadTimeout(2000);
            return conn.getResponseCode() == 200;
        } catch (Exception e) {
            return false;
        }
    }

    private void startHealthCheck() {
        int interval = properties.getBridge().getHealthCheckInterval();
        if (interval <= 0) return;

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

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

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

    /** 生成 32 字符随机 token（用于未配置时的临时降级） */
    private String generateRandomToken() {
        byte[] bytes = new byte[24];
        new java.security.SecureRandom().nextBytes(bytes);
        return java.util.HexFormat.of().formatHex(bytes);
    }
}
