package com.yaoai.api.controller;

import cn.dev33.satoken.stp.StpUtil;
import com.yaoai.agent.dto.AgentRunCommand;
import com.yaoai.agent.service.AgentRunService;
import com.yaoai.agent.sse.AgentSseManager;
import com.yaoai.api.dto.agent.AgentRunDTO;
import com.yaoai.api.dto.agent.AgentStartRequest;
import com.yaoai.common.exception.BizException;
import com.yaoai.common.exception.ErrorCode;
import com.yaoai.common.response.ApiResponse;
import com.yaoai.domain.entity.GraphRun;
import com.yaoai.domain.entity.GraphStep;
import com.yaoai.security.context.TenantContext;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.List;
import java.util.Map;

@Slf4j
@Tag(name = "Agent 制作中心")
@RestController
@RequestMapping("/agent")
@RequiredArgsConstructor
public class AgentController {

    private final AgentRunService agentRunService;
    private final AgentSseManager sseManager;

    @Operation(summary = "启动 Agent 制作流程")
    @PostMapping("/projects/{projectId}/runs")
    public ApiResponse<AgentRunDTO> startRun(@PathVariable Long projectId,
                                             @Valid @RequestBody AgentStartRequest req) {
        Long tenantId = TenantContext.get();
        GraphRun run = agentRunService.startRun(projectId, tenantId, toCommand(req));
        List<GraphStep> steps = agentRunService.getSteps(run.getId(), tenantId);
        return ApiResponse.success(AgentRunDTO.from(run, steps));
    }

    private AgentRunCommand toCommand(AgentStartRequest req) {
        AgentRunCommand command = new AgentRunCommand();
        command.setGoal(req.getGoal());
        command.setRunIntent(req.getRunIntent());
        command.setForceRegenerate(req.getForceRegenerate());
        command.setSelectedSteps(req.getSelectedSteps());
        command.setIdempotencyKey(req.getIdempotencyKey());
        AgentRunCommand.ContextOptions options = new AgentRunCommand.ContextOptions();
        if (req.getContextOptions() != null) {
            options.setUseScriptAsset(req.getContextOptions().getUseScriptAsset());
            options.setUseExistingOutline(req.getContextOptions().getUseExistingOutline());
            options.setUseExistingEpisodes(req.getContextOptions().getUseExistingEpisodes());
            options.setUseExistingAssets(req.getContextOptions().getUseExistingAssets());
            options.setUseExistingStoryboards(req.getContextOptions().getUseExistingStoryboards());
        }
        command.setContextOptions(options);
        return command;
    }

    @Operation(summary = "查询 Run 状态及所有步骤")
    @GetMapping("/runs/{runId}")
    public ApiResponse<AgentRunDTO> getRun(@PathVariable Long runId) {
        Long tenantId = TenantContext.get();
        GraphRun run = agentRunService.getRun(runId, tenantId);
        List<GraphStep> steps = agentRunService.getSteps(runId, tenantId);
        return ApiResponse.success(AgentRunDTO.from(run, steps));
    }

    @Operation(summary = "获取项目最新 Run")
    @GetMapping("/projects/{projectId}/runs/latest")
    public ApiResponse<AgentRunDTO> getLatestRun(@PathVariable Long projectId) {
        Long tenantId = TenantContext.get();
        GraphRun run = agentRunService.getLatestRun(projectId, tenantId);
        if (run == null) return ApiResponse.success(null);
        List<GraphStep> steps = agentRunService.getSteps(run.getId(), tenantId);
        return ApiResponse.success(AgentRunDTO.from(run, steps));
    }

    @Operation(summary = "SSE 实时进度流")
    @GetMapping(value = "/runs/{runId}/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter subscribe(@PathVariable Long runId,
                                @RequestHeader(value = "Authorization", required = false) String authHeader,
                                @RequestParam(required = false) String Authorization,
                                HttpServletResponse response) throws IOException {
        String token = authHeader;
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring("Bearer ".length()).trim();
        }
        if (token == null || token.isBlank()) {
            token = Authorization;
        }
        if (token == null || token.isBlank()) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Missing token");
            return null;
        }
        try {
            Object loginId = StpUtil.getLoginIdByToken(token);
            if (loginId == null) throw new RuntimeException("invalid token");
            Object tenantId = StpUtil.getSessionByLoginId(loginId).get("tenantId");
            if (tenantId != null) {
                TenantContext.set(((Number) tenantId).longValue());
            }
        } catch (Exception e) {
            log.warn("SSE auth failed: runId={}, reason={}", runId, e.getMessage());
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
            return null;
        }
        return sseManager.subscribe(runId);
    }

    @Operation(summary = "暂停 Run")
    @PostMapping("/runs/{runId}/pause")
    public ApiResponse<Void> pauseRun(@PathVariable Long runId) {
        Long tenantId = TenantContext.get();
        agentRunService.pauseRun(runId, tenantId);
        return ApiResponse.success(null);
    }

    @Operation(summary = "继续 Run")
    @PostMapping("/runs/{runId}/resume")
    public ApiResponse<Void> resumeRun(@PathVariable Long runId) {
        Long tenantId = TenantContext.get();
        agentRunService.resumeRun(runId, tenantId);
        return ApiResponse.success(null);
    }
}
