package com.cmvr.web.controller.test;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSONObject;
import com.cmvr.common.annotation.Anonymous;
import com.cmvr.common.core.controller.BaseController;
import com.cmvr.common.core.domain.AjaxResult;
import com.cmvr.llm.service.LLMAiAgentPlatformService;
import com.cmvr.test.flow.context.TaskContextManager;
import com.cmvr.test.flow.control.FlowControlService;
import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService;
import com.cmvr.test.flow.runtime.operator.edge.ti.TiTouchOperateService;
import com.cmvr.test.model.domain.TeDetectionItem;
import com.cmvr.test.model.vo.FlowActionRequestVO;
import com.cmvr.test.model.vo.TeFlowViewVO;
import com.cmvr.test.model.vo.TeTaskExecuteNormalVO;
import com.cmvr.test.model.vo.TeTaskExecuteTrailVO;
import com.cmvr.test.service.FlowActionExecutorService;
import com.cmvr.test.service.ITeDetectionItemService;
import com.cmvr.test.service.ITeNodeInstService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.annotation.PreDestroy;
import jakarta.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

@Api(tags = "测试--流程服务")
@RestController
@RequestMapping("/flow")
@RequiredArgsConstructor
public class TeFlowController extends BaseController {

    /**
     * TTS 播放接口，当前按需求固定写死在 Controller 中。
     */
    private static final String TTS_PLAY_URL = "http://localhost:8080/tts/play";

    /**
     * TTS 停止接口，停止智能体输出时同步调用。
     */
    private static final String TTS_STOP_URL = "http://localhost:8080/tts/stop";

    /**
     * 商道智能体 AppKey，当前按需求固定写死，不放入配置文件。
     */
    private static final String AI_AGENT_API_KEY = "d9etum54shheenol3apg";

    private final ITeDetectionItemService teDetectionItemService;
    private final ITeNodeInstService nodeInstService;
    private final FlowTaskRuntimeService flowTaskRuntimeService;
    private final TaskContextManager taskContextManager;
    private final FlowControlService flowControlService;
    private final FlowActionExecutorService flowActionExecutorService;
    private final TiTouchOperateService tiTouchOperateService;
    private final LLMAiAgentPlatformService llmAiAgentPlatformService;
    private final List<String> taskInstIdList = new ArrayList<>();

    /**
     * 智能体调用是阻塞式 query，这里用单线程保存当前任务句柄，便于 stop 接口中断当前请求。
     */
    private final ExecutorService aiAgentExecutor = Executors.newSingleThreadExecutor(runnable -> {
        Thread thread = new Thread(runnable, "flow-ai-agent-query");
        thread.setDaemon(true);
        return thread;
    });

    /**
     * 当前正在执行的智能体任务。当前接口按“同一时间只保留一个前端智能体调用”处理。
     */
    private volatile Future<JSONObject> currentAiAgentFuture;

    @ApiOperation("流程发布")
    @PostMapping("/publish")
    public AjaxResult publish(@RequestBody TeDetectionItem detectionItem) {
        return toAjax(teDetectionItemService.publish(detectionItem.getId()));
    }

    @ApiOperation("演示任务执行入口")
    @PostMapping("/demo")
    @Anonymous
    public AjaxResult demo(@Valid @RequestBody TeTaskExecuteNormalVO taskExecuteNormalVO) {
        if (!taskInstIdList.isEmpty()) {
            try {
                taskInstIdList.forEach(flowControlService::stop);
            } catch (Exception e) {
                // 演示入口清理旧任务失败时继续启动新任务，避免影响手动调试。
            }
            taskInstIdList.clear();
        }
        String insId = flowTaskRuntimeService.executeTask(taskExecuteNormalVO);
        taskInstIdList.add(insId);
        return AjaxResult.success();
    }

    @ApiOperation("任务执行入口")
    @PostMapping("/execute")
    @Anonymous
    public AjaxResult execute(@Valid @RequestBody TeTaskExecuteNormalVO taskExecuteNormalVO) {
        return AjaxResult.success(flowTaskRuntimeService.executeTask(taskExecuteNormalVO));
    }

    @ApiOperation("检测项试运行入口")
    @PostMapping("/executeTrial")
    public AjaxResult executeTrial(@Valid @RequestBody TeTaskExecuteTrailVO taskExecuteTrailVO) {
        return AjaxResult.success(flowTaskRuntimeService.executeTrialTask(taskExecuteTrailVO));
    }

    @ApiOperation("流程可视化")
    @PostMapping("/view")
    public AjaxResult view(@Valid @RequestBody TeFlowViewVO flowViewVO) {
        return AjaxResult.success(nodeInstService.view(flowViewVO));
    }

    @ApiOperation("清理终端")
    @GetMapping("/clear")
    public AjaxResult clear() {
        taskContextManager.clearAll();
        return AjaxResult.success();
    }

    @ApiOperation("终止任务")
    @PostMapping("/stop/{instId}")
    public AjaxResult stopTask(@PathVariable String instId) {
        flowControlService.stop(instId);
        return AjaxResult.success();
    }

    @ApiOperation("暂停任务")
    @PostMapping("/pause/{instId}")
    public AjaxResult pauseTask(@PathVariable String instId) {
        flowControlService.pause(instId);
        return AjaxResult.success();
    }

    @ApiOperation("恢复任务")
    @PostMapping("/resume/{instId}")
    public AjaxResult resumeTask(@PathVariable String instId) {
        flowControlService.resume(instId);
        return AjaxResult.success();
    }

    @PostMapping("/action")
    @ApiOperation(value = "单个节点执行",
            notes = "巡检仪表节点action=INSPECTION_METER_RECOGNIZE，payload使用InspectionMeterRecognizeConfigVO；"
                    + "人工判断节点action=INSPECTION_MANUAL_REVIEW_CREATE，payload使用InspectionManualReviewConfigVO。"
                    + "该接口用于试调节点，不会生成正式巡检任务结果")
    public AjaxResult actionExecute(
            @io.swagger.annotations.ApiParam(value = "单节点动作和参数", required = true)
            @RequestBody FlowActionRequestVO flowActionRequestVO) {
        return AjaxResult.ok(flowActionExecutorService.actionExecute(flowActionRequestVO));
    }

    /**
     * 调用商道智能体平台。
     *
     * <p>前端只需要传入 text。后端固定 action、apiKey 和 TTS 参数。
     * 调用会放入可取消任务中，前端可以通过 /flow/llm/stop 停止当前调用并停止 TTS。</p>
     */
    @GetMapping("/llm/query")
    @ApiOperation("调用商道智能体")
    public AjaxResult queryAiAgent(String text) {
        if (text == null || text.trim().isEmpty()) {
            return AjaxResult.error("text不能为空");
        }

        stopCurrentAiAgentFuture(true);

        JSONObject params = new JSONObject();
        params.put("url", TTS_PLAY_URL);
        params.put("voice", "x4_yezi");
        params.put("speed", 45);
        params.put("volume", 100);

        Future<JSONObject> future = aiAgentExecutor.submit(() -> llmAiAgentPlatformService.query(
            null,
            text.trim(),
            AI_AGENT_API_KEY,
            true,
            params
        ));
        currentAiAgentFuture = future;

        try {
            return AjaxResult.ok(future.get());
        } catch (CancellationException e) {
            return AjaxResult.error("智能体调用已停止");
        } catch (InterruptedException e) {
            future.cancel(true);
            Thread.currentThread().interrupt();
            return AjaxResult.error("智能体调用被中断");
        } catch (ExecutionException e) {
            Throwable cause = e.getCause() == null ? e : e.getCause();
            return AjaxResult.error("智能体调用失败：" + cause.getMessage());
        } finally {
            if (currentAiAgentFuture == future) {
                currentAiAgentFuture = null;
            }
        }
    }

    /**
     * 停止当前智能体调用，并通知 TTS 服务停止播放。
     *
     * <p>停止分两步：先取消当前 query 任务，触发底层 SSE 等待线程中断；
     * 再调用本地 TTS stop 接口，停止已经进入播放队列的音频。</p>
     */
    @PostMapping("/llm/stop")
    @ApiOperation("停止商道智能体和TTS")
    public AjaxResult stopAiAgent() {
        stopCurrentAiAgentFuture(false);
//        String ttsStopResult = stopTts();
        return AjaxResult.ok("ok");
    }

    @GetMapping("/testrun")
    @ApiOperation("测试接口")
    public AjaxResult testrun(@RequestParam("imageUrl") String imageUrl,
                              @RequestParam("iconUrl") String iconUrl) {
        return AjaxResult.ok(tiTouchOperateService.test(imageUrl, iconUrl));
    }

    /**
     * 取消当前智能体任务。
     *
     * @param stopTts 是否同时停止 TTS 播放
     */
    private void stopCurrentAiAgentFuture(boolean stopTts) {
        Future<JSONObject> future = currentAiAgentFuture;
        if (future != null && !future.isDone()) {
            future.cancel(true);
        }
        currentAiAgentFuture = null;
        if (stopTts) {
            stopTts();
        }
    }

    /**
     * 调用本地 TTS 停止接口。
     */
    private String stopTts() {
        try (HttpResponse response = HttpRequest.post(TTS_STOP_URL)
            .timeout(3000)
            .execute()) {
            return response.body();
        } catch (Exception e) {
            return "调用TTS停止接口失败：" + e.getMessage();
        }
    }

    /**
     * Spring 容器关闭时释放智能体执行线程。
     */
    @PreDestroy
    public void destroy() {
        stopCurrentAiAgentFuture(true);
        aiAgentExecutor.shutdownNow();
    }
}
