package tech.easyflow.publicapi.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import com.easyagents.core.message.UserMessage;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.NotBlank;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import tech.easyflow.approval.annotation.RequirePublishedAccess;
import tech.easyflow.ai.entity.Bot;
import tech.easyflow.ai.entity.ChatRequestParams;
import tech.easyflow.ai.service.BotService;
import tech.easyflow.ai.service.impl.BotServiceImpl;
import tech.easyflow.common.domain.Result;
import tech.easyflow.core.chat.protocol.sse.ChatSseUtil;
import tech.easyflow.core.runtime.ChatChannel;
import tech.easyflow.core.runtime.ChatRuntimeContext;
import tech.easyflow.system.entity.SysApiKey;
import tech.easyflow.system.service.SysApiKeyService;

import javax.annotation.Resource;
import java.math.BigInteger;

/**
 * bot 接口
 */
@RestController
@RequestMapping("/public-api/bot")
public class PublicBotController {

    @Resource
    private BotService botService;
    @Resource
    private SysApiKeyService sysApiKeyService;

    /**
     * 根据id或别名获取bot详情
     */
    @GetMapping("/getByIdOrAlias")
    @RequirePublishedAccess(resourceType = "BOT", idExpr = "#key", denyMessage = "聊天助手尚未发布")
    public Result<Bot> getByIdOrAlias(@NotBlank(message = "key不能为空") String key) {
        return Result.ok(botService.getPublishedDetail(key));
    }

    /**
     * 第三方调用聊天助手
     *
     * @return 返回SseEmitter对象，用于服务器向客户端推送聊天响应数据
     */
    @PostMapping("chat")
    @RequirePublishedAccess(resourceType = "BOT", idExpr = "#chatRequestParams.botId", denyMessage = "聊天助手尚未发布")
    public SseEmitter chat(@RequestBody ChatRequestParams chatRequestParams, HttpServletRequest request) {
        String apikey = request.getHeader(SysApiKey.KEY_Apikey);
        String requestURI = request.getRequestURI();
        if (!StringUtils.hasText(apikey)) {
           return ChatSseUtil.sendSystemError(null, "Apikey不能为空!");
        }
        sysApiKeyService.checkApikeyPermission(apikey, requestURI);
        SysApiKey sysApiKey = sysApiKeyService.getSysApiKey(apikey);
        BotServiceImpl.ChatCheckResult chatCheckResult = new BotServiceImpl.ChatCheckResult();
        int size = chatRequestParams.getMessages().size();
        String prompt = null;
        if (chatRequestParams.getMessages().get(size - 1) instanceof UserMessage) {
            prompt = ((UserMessage) chatRequestParams.getMessages().get(size - 1)).getContent();
        }
        // 前置校验：失败则直接返回错误SseEmitter
        SseEmitter errorEmitter = botService.checkChatBeforeStart(chatRequestParams.getBotId(), prompt, chatRequestParams.getConversationId(), chatCheckResult);
        if (errorEmitter != null) {
            return errorEmitter;
        }
        return botService.startPublicChat(
                chatRequestParams.getBotId(),
                prompt,
                chatRequestParams.getMessages(),
                chatCheckResult,
                buildRuntimeContext(chatCheckResult.getAiBot(), chatRequestParams.getConversationId(), prompt, sysApiKey)
        );
    }

    private ChatRuntimeContext buildRuntimeContext(Bot bot, String conversationId, String prompt, SysApiKey sysApiKey) {
        ChatRuntimeContext context = new ChatRuntimeContext();
        context.setChannel(ChatChannel.PUBLIC_API);
        context.setSessionId(new BigInteger(conversationId));
        context.setTenantId(BigInteger.ZERO);
        context.setDeptId(BigInteger.ZERO);
        context.setUserId(BigInteger.ZERO);
        context.setUserAccount("apikey:" + sysApiKey.getId());
        context.setUserName("API 调用方");
        context.setAssistantId(bot == null ? BigInteger.ZERO : bot.getId());
        context.setAssistantCode(bot == null ? null : bot.getAlias());
        context.setAssistantName(bot == null ? null : bot.getTitle());
        context.setSessionTitle(prompt != null && prompt.length() > 200 ? prompt.substring(0, 200) : prompt);
        context.setAnonymous(true);
        return context;
    }


}
