package com.cloudhandson.ddsbackoffice.service;

import com.cloudhandson.ddsbackoffice.domain.DdsMcpAuthenticatedUser;
import com.cloudhandson.ddsbackoffice.domain.DdsMcpVectorSearchResult;
import com.cloudhandson.vpdbackoffice.service.AppException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.stereotype.Service;

/** JSON-RPC surface for the DDS-only SSE MCP endpoint. */
@Service
public class DdsMcpSseService {

  private final ObjectMapper objectMapper;
  private final DdsMcpVectorSearchService vectorSearchService;

  public DdsMcpSseService(ObjectMapper objectMapper, DdsMcpVectorSearchService vectorSearchService) {
    this.objectMapper = objectMapper;
    this.vectorSearchService = vectorSearchService;
  }

  public ObjectNode handle(DdsMcpAuthenticatedUser user, JsonNode request) {
    ObjectNode response = objectMapper.createObjectNode();
    response.put("jsonrpc", "2.0");
    if (request != null && request.has("id")) {
      response.set("id", request.get("id"));
    }
    String method = request == null ? "" : request.path("method").asText("");
    try {
      ObjectNode result = switch (method) {
        case "initialize" -> initialize();
        case "notifications/initialized" -> objectMapper.createObjectNode();
        case "tools/list" -> tools();
        case "tools/call" -> toolCall(user, request.path("params"));
        default -> throw new AppException("지원하지 않는 MCP method입니다: " + method);
      };
      response.set("result", result);
    } catch (Exception exception) {
      ObjectNode error = objectMapper.createObjectNode();
      error.put("code", -32000);
      error.put("message", safeMessage(exception));
      response.set("error", error);
    }
    return response;
  }

  private ObjectNode initialize() {
    ObjectNode result = objectMapper.createObjectNode();
    result.put("protocolVersion", "2024-11-05");
    ObjectNode serverInfo = result.putObject("serverInfo");
    serverInfo.put("name", "dds-end-user-mcp");
    serverInfo.put("version", "0.1.0");
    result.putObject("capabilities").putObject("tools");
    return result;
  }

  private ObjectNode tools() {
    ObjectNode result = objectMapper.createObjectNode();
    ArrayNode tools = result.putArray("tools");
    ObjectNode search = tools.addObject();
    search.put("name", "dds_vector_search");
    search.put("description", "DDS END USER Context와 DATA GRANT로 제한된 지식 검색");
    ObjectNode schema = search.putObject("inputSchema");
    schema.put("type", "object");
    ObjectNode properties = schema.putObject("properties");
    properties.putObject("query").put("type", "string").put("description", "검색 질문");
    properties.putObject("limit").put("type", "integer").put("minimum", 1).put("maximum", 100);
    ObjectNode embeddingMode = properties.putObject("embeddingMode");
    embeddingMode.put("type", "string");
    embeddingMode.putArray("enum").add("DEMO").add("AI");
    embeddingMode.put("default", "DEMO");
    schema.putArray("required").add("query");
    schema.put("additionalProperties", false);
    return result;
  }

  private ObjectNode toolCall(DdsMcpAuthenticatedUser user, JsonNode params) {
    if (!"dds_vector_search".equals(params.path("name").asText(""))) {
      throw new AppException("DDS MCP tool을 찾을 수 없습니다.");
    }
    JsonNode arguments = params.path("arguments");
    DdsMcpVectorSearchResult search = vectorSearchService.search(
        user.principal(),
        arguments.path("query").asText(""),
        arguments.path("limit").asInt(10),
        arguments.path("embeddingMode").asText("DEMO"));
    ObjectNode body = objectMapper.createObjectNode();
    body.put("query", search.query());
    body.put("embeddingMode", search.embeddingMode());
    body.put("rowCount", search.rowCount());
    body.set("rows", objectMapper.valueToTree(search.rows()));
    ObjectNode result = objectMapper.createObjectNode();
    result.putArray("content").addObject().put("type", "text")
        .put("text", pretty(body));
    result.put("isError", false);
    return result;
  }

  private String pretty(ObjectNode body) {
    try {
      return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(body);
    } catch (Exception exception) {
      return "DDS MCP 결과를 직렬화할 수 없습니다.";
    }
  }

  private String safeMessage(Exception exception) {
    String message = exception.getMessage();
    return message == null || message.isBlank() ? "DDS MCP 요청을 처리할 수 없습니다." : message;
  }
}
