package com.agent.management.service;

import com.agent.management.engine.ExecutionLog;
import com.agent.management.engine.WorkflowRunEvent;
import com.agent.management.engine.hermes.ClarifyHooks;
import com.agent.management.engine.hermes.HermesBridgeClient;
import com.agent.management.external.SseEventBus;
import com.agent.management.model.entity.AiModel;
import com.agent.management.model.entity.ChatMessage;
import com.agent.management.model.entity.ChatSession;
import com.agent.management.repository.ChatMessageRepository;
import com.agent.management.repository.ChatSessionRepository;
import com.agent.management.repository.WorkflowPauseRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import jakarta.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Agent 对话 Run 编排器。
 *
 * <p>对应设计文档 {@code docs/design/agent-chat-page-design.md} §4.3.4。
 * 职责：</p>
 * <ol>
 *   <li>写 user 消息（编辑场景由前端先调 PATCH，这里跳过）</li>
 *   <li>解析模型配置 / 技能系统提示</li>
 *   <li>生成 runId，注册 {@link SseEventBus}</li>
 *   <li>写 assistant 占位消息（{@code RUNNING}）</li>
 *   <li>异步调 {@link HermesBridgeClient#run}：
 *     <ul>
 *       <li>sink 回调 → SSE 推送 + 累积到日志缓冲区（达阈值批量落库）</li>
 *       <li>{@link ClarifyHooks#wrap} 包装拦截 {@code clarify_request} 落 WorkflowPause 表</li>
 *     </ul>
 *   </li>
 *   <li>完成时 {@code markSuccess} + {@code touch} + {@code autoTitleIfNeeded}；
 *       异常时 {@code markFailed} + 推 {@code workflow_error}</li>
 * </ol>
 */
@Slf4j
@Service
public class ChatRunService {

    private final ChatSessionRepository sessionRepo;
    private final ChatMessageRepository messageRepo;
    private final ChatSessionService sessionService;
    private final ChatMessageService messageService;
    private final ChatMessageLogService logService;
    private final HermesBridgeClient hermesBridgeClient;
    private final SseEventBus eventBus;
    private final AiModelService aiModelService;
    private final SkillService skillService;
    private final WorkflowPauseRepository pauseRepo;
    private final ExecutorService executor;

    @Autowired
    public ChatRunService(ChatSessionRepository sessionRepo,
                          ChatMessageRepository messageRepo,
                          ChatSessionService sessionService,
                          ChatMessageService messageService,
                          ChatMessageLogService logService,
                          HermesBridgeClient hermesBridgeClient,
                          SseEventBus eventBus,
                          AiModelService aiModelService,
                          SkillService skillService,
                          WorkflowPauseRepository pauseRepo) {
        this.sessionRepo = sessionRepo;
        this.messageRepo = messageRepo;
        this.sessionService = sessionService;
        this.messageService = messageService;
        this.logService = logService;
        this.hermesBridgeClient = hermesBridgeClient;
        this.eventBus = eventBus;
        this.aiModelService = aiModelService;
        this.skillService = skillService;
        this.pauseRepo = pauseRepo;
        this.executor = Executors.newFixedThreadPool(
                Math.max(8, Runtime.getRuntime().availableProcessors() * 2),
                r -> {
                    Thread t = new Thread(r, "chat-run");
                    t.setDaemon(true);
                    return t;
                });
    }

    /**
     * 容器关闭时停止后台 run 线程，等待正在进行中的 sink flush 完成。
     */
    @PreDestroy
    public void shutdown() {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 启动一轮对话 run。
     *
     * @param sessionId       会话 id
     * @param userMessage     用户输入（若 parentMessageId 是新建的 user 消息，可为 null）
     * @param modelId         模型 id（null 时用会话默认）
     * @param skillFolder     技能目录名（null 表示无技能）
     * @param maxIterations   Hermes 最大迭代数（null 用默认 100）
     * @param parentMessageId 父消息 id。三种语义：
     *                        <ul>
     *                          <li>常规对话：上一条激活消息的 id</li>
     *                          <li>编辑 user 消息：前端先调 PATCH 创建了新 user 消息，这里是其 id</li>
     *                          <li>会话首条：null</li>
     *                        </ul>
     * @return RunStartResult，含 runId 与 assistantMsgId
     */
    public RunStartResult startRun(Long sessionId, String userMessage, Long modelId,
                                    String skillFolder, Integer maxIterations,
                                    Long parentMessageId) {
        ChatSession session = sessionRepo.findById(sessionId)
                .orElseThrow(() -> new IllegalArgumentException("会话不存在: " + sessionId));

        // 1. 写/复用 user 消息
        Long userMsgId;
        boolean parentIsUser = parentMessageId != null
                && messageRepo.findById(parentMessageId)
                        .filter(m -> "USER".equals(m.getRole()))
                        .isPresent();
        if (parentIsUser) {
            // 编辑场景：parentMessageId 已是新建的 user 消息
            userMsgId = parentMessageId;
        } else {
            ChatMessage userMsg = new ChatMessage();
            userMsg.setSessionId(sessionId);
            userMsg.setParentId(parentMessageId);
            userMsg.setIsActive(true);
            userMsg.setBranchOrder(nextBranchOrder(parentMessageId));
            userMsg.setRole("USER");
            userMsg.setContent(userMessage != null ? userMessage : "");
            userMsg.setStatus("SENT");
            userMsg.setModelId(modelId);
            userMsg.setSkillFolder(skillFolder);
            messageRepo.save(userMsg);
            userMsgId = userMsg.getId();
        }

        // 2. 解析模型配置
        Long effectiveModelId = modelId != null ? modelId : session.getModelId();
        Map<String, String> modelConfig = effectiveModelId != null
                ? buildModelConfig(effectiveModelId) : null;

        // 3. 解析技能系统提示
        String effectiveSkill = skillFolder != null ? skillFolder : session.getSkillFolder();
        String systemPrompt = effectiveSkill != null
                ? skillService.getSkillFullContent(effectiveSkill) : null;

        // 4. 生成 runId，注册 SSE 总线
        String runId = UUID.randomUUID().toString().substring(0, 8);
        eventBus.register(runId);

        // 5. 写 assistant 占位消息（parent = userMsgId）
        ChatMessage assistantMsg = new ChatMessage();
        assistantMsg.setSessionId(sessionId);
        assistantMsg.setParentId(userMsgId);
        assistantMsg.setIsActive(true);
        assistantMsg.setBranchOrder(0);
        assistantMsg.setRunId(runId);
        assistantMsg.setRole("ASSISTANT");
        assistantMsg.setContent("");
        assistantMsg.setStatus("RUNNING");
        assistantMsg.setModelId(effectiveModelId);
        assistantMsg.setSkillFolder(effectiveSkill);
        messageRepo.save(assistantMsg);

        // 6. 异步调 Bridge
        final String finalUserMessage = userMessage;
        final int iterations = maxIterations != null ? maxIterations : 100;
        final Long assistantMsgId = assistantMsg.getId();
        final String hermesSession = session.getHermesSession();

        executor.submit(() -> runInternal(
                runId, assistantMsgId, sessionId,
                systemPrompt, finalUserMessage, iterations,
                hermesSession, modelConfig));

        return new RunStartResult(runId, assistantMsgId);
    }

    /**
     * 提交 clarify 答案，恢复对应的暂停 run。
     *
     * <p>Bridge 端收到答案后会立即继续 SSE 流，{@link ChatRunService#runInternal}
     * 中的 sink 回调会继续落日志直到完成。</p>
     */
    public boolean submitClarifyAnswer(String clarifyId, String answer) {
        return hermesBridgeClient.submitClarifyAnswer(clarifyId, answer);
    }

    /* ============== 内部 ============== */

    private void runInternal(String runId, Long assistantMsgId, Long sessionId,
                              String systemPrompt, String userMessage, int iterations,
                              String hermesSession, Map<String, String> modelConfig) {
        List<ExecutionLog> buffer = new ArrayList<>();
        // sink 先包装 clarify 拦截器（落 WorkflowPause），再包装 SSE 推送 + 缓冲
        com.agent.management.engine.NodeStreamSink sink = ClarifyHooks.wrap(
                (nodeId, kind, content, toolName) -> {
                    // 1) SSE 推送
                    WorkflowRunEvent evt = WorkflowRunEvent.nodeStream(runId, "agent", kind, content, toolName);
                    eventBus.publish(runId, evt.getType(), evt);
                    // 2) 累积到缓冲区
                    buffer.add(toExecutionLog(kind, content, toolName));
                    if (buffer.size() >= ChatMessageLogService.FLUSH_THRESHOLD) {
                        flushBuffer(assistantMsgId, buffer);
                    }
                },
                runId,
                pauseRepo);

        try {
            String finalText = hermesBridgeClient.run(
                    systemPrompt, userMessage, iterations,
                    null, null,
                    "agent", sink, hermesSession,
                    modelConfig).getFinalText();
            // 最终 flush 残留日志
            flushBuffer(assistantMsgId, buffer);
            messageService.markSuccess(assistantMsgId, finalText != null ? finalText : "");
            sessionService.touch(sessionId);
            sessionService.autoTitleIfNeeded(sessionId);
            // 推送 workflow_complete 事件（前端据此关闭 loading）
            Map<String, Object> outputs = new HashMap<>();
            if (finalText != null) {
                outputs.put("reply", finalText);
            }
            eventBus.publish(runId, "workflow_complete",
                    WorkflowRunEvent.workflowComplete(runId, outputs, null));
        } catch (Exception e) {
            log.error("[ChatRunService] run 失败 runId={} assistantMsgId={}: {}", runId, assistantMsgId, e.getMessage(), e);
            flushBuffer(assistantMsgId, buffer);
            String errMsg = e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName();
            messageService.markFailed(assistantMsgId, errMsg);
            eventBus.publish(runId, "workflow_error",
                    WorkflowRunEvent.workflowError(runId, errMsg));
        }
    }

    /** 同步 flush 残留缓冲区（保留当前 startSeq） */
    private void flushBuffer(Long messageId, List<ExecutionLog> buffer) {
        if (buffer.isEmpty()) {
            return;
        }
        int startSeq = (int) logService.countByMessage(messageId);
        try {
            int written = logService.appendBatch(messageId, buffer, startSeq);
            if (written > 0) {
                buffer.clear();
            }
        } catch (Exception e) {
            log.warn("[ChatRunService] flush 日志失败（不影响主流程）: {}", e.getMessage());
            buffer.clear();
        }
    }

    /** 把流式回调的三元组映射为 {@link ExecutionLog}（与字段拆解保持一致） */
    private ExecutionLog toExecutionLog(String kind, String content, String toolName) {
        ExecutionLog.Type type = parseKind(kind);
        switch (type) {
            case TOOL_CALL:
            case TOOL_RESULT:
                return new ExecutionLog(type, toolName != null ? toolName : kind, content);
            case STEP:
            case TOOL_PROGRESS:
            case TODO_UPDATE:
            case CLARIFY_REQUEST:
                return new ExecutionLog(type, content, null);
            default:
                return new ExecutionLog(type, content, null);
        }
    }

    /** 字符串 kind → ExecutionLog.Type 枚举；未知值回落到 INFO */
    private ExecutionLog.Type parseKind(String kind) {
        if (kind == null) {
            return ExecutionLog.Type.INFO;
        }
        try {
            return ExecutionLog.Type.valueOf(kind.toUpperCase());
        } catch (IllegalArgumentException e) {
            return ExecutionLog.Type.INFO;
        }
    }

    /** 同 parent 的下个 branchOrder；首条为 0 */
    private int nextBranchOrder(Long parentId) {
        if (parentId == null) {
            return 0;
        }
        Integer max = messageRepo.maxBranchOrderByParent(parentId);
        return (max == null ? -1 : max) + 1;
    }

    /** 从 AiModel 实体构造 HermesBridgeClient 需要的 modelConfig Map */
    private Map<String, String> buildModelConfig(Long modelId) {
        AiModel model = aiModelService.getModel(modelId);
        if (model == null) {
            return null;
        }
        Map<String, String> cfg = new HashMap<>();
        cfg.put("modelId", String.valueOf(model.getId()));
        if (model.getBaseUrl() != null) cfg.put("baseUrl", model.getBaseUrl());
        if (model.getApiKey() != null) cfg.put("apiKey", model.getApiKey());
        if (model.getModelName() != null) cfg.put("modelName", model.getModelName());
        return cfg;
    }

    /** 启动 run 的返回结果 */
    public record RunStartResult(String runId, Long assistantMessageId) {
    }
}
