package com.agent.management.service.impl;

import com.agent.management.config.EmbeddingBridgeProperties;
import com.agent.management.config.MilvusProperties;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
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.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;

/**
 * 管理本地 Embedding Bridge Python 子进程的生命周期。
 * 仅在 app.embedding-bridge.enabled=true 时激活。
 */
@Slf4j
@Component
@ConditionalOnProperty(name = "app.embedding-bridge.enabled", havingValue = "true")
public class EmbeddingBridgeProcessManager {

    private final EmbeddingBridgeProperties props;
    private final MilvusProperties milvusProps;
    private final EmbeddingBridgeClient client;

    private Process process;
    private final AtomicBoolean starting = new AtomicBoolean(false);
    private ScheduledExecutorService healthScheduler;
    private volatile boolean stopped = false;

    public EmbeddingBridgeProcessManager(EmbeddingBridgeProperties props, MilvusProperties milvusProps, EmbeddingBridgeClient client) {
        this.props = props;
        this.milvusProps = milvusProps;
        this.client = client;
    }

    @PostConstruct
    public void start() {
        log.info("[EmbeddingBridge] 启动子进程...");
        starting.set(true);

        try {
            String scriptPath = resolveScriptPath();
            String pythonPath = props.getPythonPath();
            int port = props.getPort();

            ProcessBuilder pb = new ProcessBuilder(
                    pythonPath, scriptPath,
                    "--port", String.valueOf(port),
                    "--host", props.getHost()
            );
            pb.redirectErrorStream(true);

            Map<String, String> env = pb.environment();
            env.put("PYTHONUNBUFFERED", "1");
            env.put("PYTHONIOENCODING", "utf-8");
            env.put("PYTHONUTF8", "1");
            env.put("EMBEDDING_MODEL", props.getEmbeddingModel());
            env.put("EMBEDDING_DEVICE", props.getEmbeddingDevice());
            env.put("DENSE_EMBEDDING_DIM", String.valueOf(props.getDenseEmbeddingDim()));
            env.put("MILVUS_HOST", milvusProps.getHost());
            env.put("MILVUS_PORT", String.valueOf(milvusProps.getPort()));
            env.put("MILVUS_COLLECTION", milvusProps.getCollection());

            String authToken = props.getAuthToken();
            if (authToken == null || authToken.isBlank()) {
                authToken = generateRandomToken();
                log.warn("[EmbeddingBridge] auth-token 未配置，已生成临时 token（重启后变化，建议显式配置）");
                props.setAuthToken(authToken);
            }
            env.put("EMBEDDING_BRIDGE_AUTH_TOKEN", authToken);

            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("[EmbeddingBridge] {}", line);
                    }
                } catch (IOException e) {
                    if (!stopped) {
                        log.warn("[EmbeddingBridge] 输出流关闭: {}", e.getMessage());
                    }
                }
            }, "embedding-bridge-output");
            outputReader.setDaemon(true);
            outputReader.start();

            long deadline = System.currentTimeMillis() + props.getStartupTimeout() * 1000L;
            while (System.currentTimeMillis() < deadline) {
                Thread.sleep(1000);
                if (client.health()) {
                    log.info("[EmbeddingBridge] 子进程启动成功，端口: {}", port);
                    starting.set(false);
                    startHealthCheck();
                    return;
                }
            }

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

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

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

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

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

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

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

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

    private String generateRandomToken() {
        byte[] bytes = new byte[24];
        new java.security.SecureRandom().nextBytes(bytes);
        return java.util.HexFormat.of().formatHex(bytes);
    }
}
