package api

import (
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"

	"oci-portal/internal/aiwire"
	"oci-portal/internal/service"
)

// audioSpeech 是 OpenAI /ai/v1/audio/speech 端点(TTS,直通兼容面)。
//
// @Summary  OpenAI Audio Speech 兼容端点(文本转语音)
// @Tags     AI 网关
// @Param    body body aiwire.SpeechRequest true "OpenAI audio speech 请求体(model/input 必填,voice 见 xAI Grok Voice 列表,language 缺省 auto;未列字段原样透传)"
// @Success  200 {file} binary "音频字节(Content-Type 透传上游,默认 audio/mpeg)"
// @Router   /ai/v1/audio/speech [post]
func (h *aiGatewayHandler) audioSpeech(c *gin.Context) {
	raw, err := c.GetRawData()
	if err != nil {
		aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error())
		return
	}
	modelName, body, err := service.SpeechBodyNormalize(raw)
	if err != nil {
		aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error())
		return
	}
	h.speechRespond(c, "speech", modelName, raw, body)
}

// tts 是 xAI 官方格式 TTS 端点(/ai/v1/tts),转换为上游 OpenAI 兼容形态后复用 Speech 编排。
//
// @Summary  xAI 官方格式文本转语音端点
// @Tags     AI 网关
// @Param    body body aiwire.TtsRequest true "xAI TTS 请求体(text/language 必填,voice_id 缺省 eve;model 为网关扩展,缺省 xai.grok-tts;未列字段原样透传)"
// @Success  200 {file} binary "音频字节(Content-Type 透传上游,默认 audio/mpeg)"
// @Router   /ai/v1/tts [post]
func (h *aiGatewayHandler) tts(c *gin.Context) {
	raw, err := c.GetRawData()
	if err != nil {
		aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error())
		return
	}
	modelName, body, err := service.TtsBodyConvert(raw)
	if err != nil {
		aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error())
		return
	}
	h.speechRespond(c, "tts", modelName, raw, body)
}

// speechRespond 是 audioSpeech / tts 的公共主体:白名单校验、上游调用、日志与音频响应。
func (h *aiGatewayHandler) speechRespond(c *gin.Context, endpoint, modelName string, raw, body []byte) {
	if !checkKeyModel(c, modelName) {
		return
	}
	start := time.Now()
	audio, contentType, meta, err := h.gw.Speech(c.Request.Context(), modelName, body, keyGroup(c))
	entry := h.logEntry(c, endpoint, modelName, false, meta, start)
	if err != nil {
		upstreamError(c, err)
		entry.ErrMsg = err.Error()
		h.logFailure(c, entry, string(raw))
		return
	}
	entry.Status = http.StatusOK
	callID := h.gw.LogCall(entry)
	h.maybeLogContent(c, callID, endpoint, modelName, false, string(raw), nil)
	if contentType == "" {
		contentType = "audio/mpeg"
	}
	c.Data(http.StatusOK, contentType, audio)
}

// rerank 是 /ai/v1/rerank 端点(Jina / Cohere 风格文档重排)。
//
// @Summary  文档重排端点(Cohere Rerank)
// @Tags     AI 网关
// @Param    body body aiwire.RerankRequest true "重排请求体(model/query/documents 必填,可选 top_n/return_documents)"
// @Success  200 {object} aiwire.RerankResponse "重排结果(results[].index 指向入参下标)"
// @Router   /ai/v1/rerank [post]
func (h *aiGatewayHandler) rerank(c *gin.Context) {
	var req aiwire.RerankRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error())
		return
	}
	if strings.TrimSpace(req.Model) == "" || strings.TrimSpace(req.Query) == "" || len(req.Documents) == 0 {
		aiError(c, http.StatusBadRequest, "invalid_request_error", "model、query 与 documents 不能为空")
		return
	}
	if !checkKeyModel(c, req.Model) {
		return
	}
	start := time.Now()
	resp, meta, err := h.gw.Rerank(c.Request.Context(), req, keyGroup(c))
	entry := h.logEntry(c, "rerank", req.Model, false, meta, start)
	if err != nil {
		upstreamError(c, err)
		entry.ErrMsg = err.Error()
		h.logFailure(c, entry, req)
		return
	}
	entry.Status = http.StatusOK
	callID := h.gw.LogCall(entry)
	h.maybeLogContent(c, callID, "rerank", req.Model, false, req, resp)
	c.JSON(http.StatusOK, resp)
}

// moderations 是 /ai/v1/moderations 端点(OpenAI 外壳映射 OCI Guardrails)。
//
// @Summary  内容审核端点(OCI Guardrails)
// @Tags     AI 网关
// @Param    body body aiwire.ModerationsRequest true "审核请求体(input 为字符串或字符串数组,单次至多 8 条;model 接受但忽略)"
// @Success  200 {object} aiwire.ModerationsResponse "审核结果(categories/category_scores 为 overall/blocklist/prompt_injection,pii 为扩展字段)"
// @Router   /ai/v1/moderations [post]
func (h *aiGatewayHandler) moderations(c *gin.Context) {
	var req aiwire.ModerationsRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error())
		return
	}
	inputs, err := service.ModerationInputs(req.Input)
	if err != nil {
		aiError(c, http.StatusBadRequest, "invalid_request_error", err.Error())
		return
	}
	start := time.Now()
	resp, meta, err := h.gw.Moderations(c.Request.Context(), aiRandID("modr_"), inputs, keyGroup(c))
	entry := h.logEntry(c, "moderations", "oci-guardrails", false, meta, start)
	if err != nil {
		upstreamError(c, err)
		entry.ErrMsg = err.Error()
		h.logFailure(c, entry, req)
		return
	}
	entry.Status = http.StatusOK
	callID := h.gw.LogCall(entry)
	h.maybeLogContent(c, callID, "moderations", "oci-guardrails", false, req, resp)
	c.JSON(http.StatusOK, resp)
}
