// Package controller 提供 transcribe 模块的 admin HTTP 接口
package controller

import (
	"encoding/json"
	"errors"
	"net/http"
	"strconv"

	"github.com/echochat/backend/app/dto"
	"github.com/echochat/backend/app/transcribe/dao"
	"github.com/echochat/backend/app/transcribe/model"
	"github.com/echochat/backend/app/transcribe/service"
	"github.com/echochat/backend/pkg/utils"
	"github.com/gin-gonic/gin"
)

// TranscribeController admin 端转写控制器
type TranscribeController struct {
	svc *service.TranscribeService
}

// NewTranscribeController 创建实例
func NewTranscribeController(svc *service.TranscribeService) *TranscribeController {
	return &TranscribeController{svc: svc}
}

// GetTranscript GET /admin/recordings/:id/transcript
//
// 返回值：
//   - 200 + transcript：存在时返回最新状态
//   - 200 + null：尚未发起转写（前端据此显示"开始转写"按钮）
func (ctl *TranscribeController) GetTranscript(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil || id <= 0 {
		utils.ResponseBadRequest(c, "无效的录制 ID")
		return
	}

	t, err := ctl.svc.GetByRecording(c.Request.Context(), id)
	if err != nil {
		utils.ResponseError(c, "查询转写失败")
		return
	}
	utils.ResponseOK(c, toDTO(t))
}

// SubmitTranscribe POST /admin/recordings/:id/transcribe
//
// body: { force: bool, language: string }
//
// 行为：异步启动 STT，返回 running 状态快照
func (ctl *TranscribeController) SubmitTranscribe(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil || id <= 0 {
		utils.ResponseBadRequest(c, "无效的录制 ID")
		return
	}

	var req dto.AdminTranscribeRequest
	// body 可选；POST 不带 body 也允许（默认 force=false language=""）
	_ = c.ShouldBindJSON(&req)

	t, err := ctl.svc.Submit(c.Request.Context(), id, req.Force, req.Language)
	if err != nil {
		ctl.handleError(c, err, t)
		return
	}
	utils.ResponseOK(c, toDTO(t))
}

// handleError 统一业务错误映射
func (ctl *TranscribeController) handleError(c *gin.Context, err error, t *model.Transcript) {
	switch {
	case errors.Is(err, service.ErrRecordingNotFound):
		utils.ResponseNotFound(c, err.Error())
	case errors.Is(err, service.ErrRecordingNotReady):
		utils.ResponseBadRequest(c, err.Error())
	case errors.Is(err, service.ErrSTTNotConfigured), errors.Is(err, dao.ErrLLMSourceDisabled):
		// 503 表示服务暂不可用，前端可据此提示"请联系管理员配置 STT"
		c.JSON(http.StatusServiceUnavailable, gin.H{
			"code":    503,
			"message": "语音转写服务未配置或不可用",
			"data":    nil,
		})
	case errors.Is(err, service.ErrTranscribeRunning):
		// 已在跑：返回当前进行中行，前端可继续轮询
		c.JSON(http.StatusAccepted, gin.H{
			"code":    0,
			"message": "已有转写任务进行中",
			"data":    toDTO(t),
		})
	case errors.Is(err, dao.ErrNoActiveSTT):
		utils.ResponseBadRequest(c, "未找到可用的 STT 模型或 API Key，请检查 LLM 配置中心")
	default:
		utils.ResponseError(c, "发起转写失败: "+err.Error())
	}
}

// toDTO 模型转 DTO，segments JSON 解码 + 状态中文标签
func toDTO(t *model.Transcript) *dto.AdminTranscriptDTO {
	if t == nil {
		return nil
	}
	segs := []dto.AdminTranscriptSeg{}
	if t.Segments != "" {
		_ = json.Unmarshal([]byte(t.Segments), &segs)
	}
	return &dto.AdminTranscriptDTO{
		ID:           t.ID,
		RecordingID:  t.RecordingID,
		RoomID:       t.RoomID,
		Status:       t.Status,
		StatusLabel:  statusLabel(t.Status),
		Text:         t.Text,
		Segments:     segs,
		Language:     t.Language,
		DurationSec:  t.DurationSec,
		ProviderCode: t.ProviderCode,
		ModelCode:    t.ModelCode,
		ErrorMsg:     t.ErrorMsg,
		StartedAt:    dto.FormatTranscriptTimePtr(t.StartedAt),
		FinishedAt:   dto.FormatTranscriptTimePtr(t.FinishedAt),
		CreatedAt:    dto.FormatTranscriptTime(t.CreatedAt),
		UpdatedAt:    dto.FormatTranscriptTime(t.UpdatedAt),
	}
}

func statusLabel(s string) string {
	switch s {
	case model.TranscriptStatusPending:
		return "待处理"
	case model.TranscriptStatusRunning:
		return "转写中"
	case model.TranscriptStatusReady:
		return "已就绪"
	case model.TranscriptStatusFailed:
		return "失败"
	default:
		return s
	}
}
