package org.dromara.ai.controller.app;

import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.ai.domain.dto.AiChatRequest;
import org.dromara.ai.domain.dto.AiChatResponse;
import org.dromara.ai.service.AiChatService;
import org.dromara.common.core.domain.R;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.web.core.BaseController;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
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.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * AI聊天控制器
 * 提供AI聊天相关的REST API接口
 *
 * @author pengles
 */
@Slf4j
@RestController
@RequestMapping("/ai/chat")
@RequiredArgsConstructor
public class AiChatController extends BaseController {

    private final AiChatService aiChatService;
    private final org.dromara.ai.service.AiChatHistoryService chatHistoryService;

    /**
     * 同步聊天对话
     *
     * @param request 聊天请求
     * @return 聊天响应
     */
    @PostMapping("/sync")
    @Log(title = "AI聊天", businessType = BusinessType.OTHER)
    public R<AiChatResponse> chat(@Validated @RequestBody AiChatRequest request) {
        log.info("接收到AI聊天请求 - 用户: {}, 模型: {}", request.getUserId(), request.getModel());

        try {
            AiChatResponse response = aiChatService.chat(request);
            return R.ok(response);
        } catch (Exception e) {
            log.error("AI聊天失败", e);
            return R.fail("AI聊天失败: " + e.getMessage());
        }
    }

    /**
     * 异步聊天对话
     *
     * @param request 聊天请求
     * @return 异步聊天响应
     */
    @PostMapping("/async")
    @Log(title = "AI异步聊天", businessType = BusinessType.OTHER)
    public R<CompletableFuture<AiChatResponse>> chatAsync(@Validated @RequestBody AiChatRequest request) {
        log.info("接收到AI异步聊天请求 - 用户: {}, 模型: {}", request.getUserId(), request.getModel());

        try {
            CompletableFuture<AiChatResponse> future = aiChatService.chatAsync(request);
            return R.ok(future);
        } catch (Exception e) {
            log.error("AI异步聊天启动失败", e);
            return R.fail("AI异步聊天启动失败: " + e.getMessage());
        }
    }

    /**
     * 流式聊天对话 (SSE)
     *
     * @param request 聊天请求
     * @return SSE流
     */
    @PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @Log(title = "AI流式聊天", businessType = BusinessType.OTHER)
    public SseEmitter chatStream(@Validated @RequestBody AiChatRequest request) {
        log.info("接收到AI流式聊天请求 - 用户: {}, 模型: {}", request.getUserId(), request.getModel());

        SseEmitter emitter = new SseEmitter(TimeUnit.MINUTES.toMillis(10)); // 10分钟超时

        try {
            aiChatService.chatStream(request, new AiChatService.StreamCallback() {
                @Override
                public void onChunk(String chunk) {
                    try {
                        emitter.send(SseEmitter.event()
                                .name("chunk")
                                .data(chunk));
                    } catch (IOException e) {
                        log.error("发送SSE数据块失败", e);
                        emitter.completeWithError(e);
                    }
                }

                @Override
                public void onComplete(AiChatResponse response) {
                    try {
                        emitter.send(SseEmitter.event()
                                .name("complete")
                                .data(response));
                        emitter.complete();
                    } catch (IOException e) {
                        log.error("发送SSE完成事件失败", e);
                        emitter.completeWithError(e);
                    }
                }

                @Override
                public void onError(Throwable error) {
                    log.error("AI流式聊天失败", error);
                    try {
                        emitter.send(SseEmitter.event()
                                .name("error")
                                .data("AI流式聊天失败: " + error.getMessage()));
                    } catch (IOException e) {
                        log.error("发送SSE错误事件失败", e);
                    }
                    emitter.completeWithError(error);
                }
            });

        } catch (Exception e) {
            log.error("AI流式聊天启动失败", e);
            emitter.completeWithError(e);
        }

        return emitter;
    }

    /**
     * 流式聊天对话 (WebSocket风格的分块响应)
     *
     * @param request  聊天请求
     * @param response HTTP响应
     */
    @PostMapping("/stream-chunks")
    @Log(title = "AI流式聊天分块", businessType = BusinessType.OTHER)
    public void chatStreamChunks(@Validated @RequestBody AiChatRequest request,
                                 HttpServletResponse response) {
        log.info("接收到AI流式聊天分块请求 - 用户: {}, 模型: {}", request.getUserId(), request.getModel());

        response.setContentType("text/plain; charset=utf-8");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Connection", "keep-alive");

        try {
            aiChatService.chatStream(request, new AiChatService.StreamCallback() {
                @Override
                public void onChunk(String chunk) {
                    try {
                        response.getWriter().write(chunk);
                        response.getWriter().flush();
                    } catch (IOException e) {
                        log.error("写入响应块失败", e);
                    }
                }

                @Override
                public void onComplete(AiChatResponse chatResponse) {
                    try {
                        response.getWriter().write("\n[DONE]\n");
                        response.getWriter().flush();
                        response.getWriter().close();
                    } catch (IOException e) {
                        log.error("完成响应写入失败", e);
                    }
                }

                @Override
                public void onError(Throwable error) {
                    try {
                        response.getWriter().write("\n[ERROR]: " + error.getMessage() + "\n");
                        response.getWriter().flush();
                        response.getWriter().close();
                    } catch (IOException e) {
                        log.error("写入错误响应失败", e);
                    }
                }
            });

        } catch (Exception e) {
            log.error("AI流式聊天分块启动失败", e);
            try {
                response.getWriter().write("\n[ERROR]: " + e.getMessage() + "\n");
                response.getWriter().flush();
                response.getWriter().close();
            } catch (IOException ioException) {
                log.error("写入启动错误响应失败", ioException);
            }
        }
    }

    /**
     * 批量聊天对话
     *
     * @param requests 聊天请求列表
     * @return 批量聊天响应
     */
    @PostMapping("/batch")
    @Log(title = "AI批量聊天", businessType = BusinessType.OTHER)
    public R<List<AiChatResponse>> chatBatch(@Validated @RequestBody List<AiChatRequest> requests) {
        log.info("接收到AI批量聊天请求 - 请求数量: {}", requests.size());

        try {
            List<CompletableFuture<AiChatResponse>> futures = aiChatService.chatBatch(requests);
            List<AiChatResponse> responses = aiChatService.waitForBatchCompletion(futures);
            return R.ok(responses);
        } catch (Exception e) {
            log.error("AI批量聊天失败", e);
            return R.fail("AI批量聊天失败: " + e.getMessage());
        }
    }

    /**
     * 获取聊天历史
     *
     * @param sessionId 会话ID
     * @param limit     限制数量
     * @return 聊天历史
     */
    @GetMapping("/history/{sessionId}")
    public R<List<AiChatRequest.AiMessage>> getChatHistory(
            @PathVariable String sessionId,
            @RequestParam(defaultValue = "50") Integer limit) {
        log.info("获取聊天历史 - 会话: {}, 限制: {}", sessionId, limit);

        try {
            List<AiChatRequest.AiMessage> history = chatHistoryService.getHistory(sessionId, limit);
            return R.ok(history);
        } catch (Exception e) {
            log.error("获取聊天历史失败", e);
            return R.fail("获取聊天历史失败: " + e.getMessage());
        }
    }

    /**
     * 清除聊天历史
     *
     * @param sessionId 会话ID
     * @return 操作结果
     */
    @DeleteMapping("/history/{sessionId}")
    @Log(title = "清除聊天历史", businessType = BusinessType.DELETE)
    public R<Void> clearChatHistory(@PathVariable String sessionId) {
        log.info("清除聊天历史 - 会话: {}", sessionId);

        try {
            chatHistoryService.clearHistory(sessionId);
            return R.ok();
        } catch (Exception e) {
            log.error("清除聊天历史失败", e);
            return R.fail("清除聊天历史失败: " + e.getMessage());
        }
    }

    /**
     * 获取会话统计信息
     *
     * @param sessionId 会话ID
     * @return 统计信息
     */
    @GetMapping("/stats/{sessionId}")
    public R<org.dromara.ai.service.AiChatHistoryService.SessionStats> getSessionStats(@PathVariable String sessionId) {
        log.info("获取会话统计 - 会话: {}", sessionId);

        try {
            org.dromara.ai.service.AiChatHistoryService.SessionStats stats = chatHistoryService.getSessionStats(sessionId);
            return R.ok(stats);
        } catch (Exception e) {
            log.error("获取会话统计失败", e);
            return R.fail("获取会话统计失败: " + e.getMessage());
        }
    }
}