// Package controller 提供 admin 模块的 HTTP 入口（会议管理）
package controller

import (
	"errors"
	"strconv"

	"github.com/echochat/backend/app/admin/service"
	"github.com/echochat/backend/app/dto"
	meetingService "github.com/echochat/backend/app/meeting/service"
	"github.com/echochat/backend/pkg/logs"
	"github.com/echochat/backend/pkg/utils"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// MeetingManageController 管理端会议管理 HTTP 控制器
//
// 路由（在 admin/router.go 中挂载到 /api/v1/admin/meetings 下，JWT + admin 角色）：
//   - GET /api/v1/admin/meetings        分页列表 + 多条件筛选
//   - GET /api/v1/admin/meetings/stats  会议管理摘要统计
//   - GET /api/v1/admin/meetings/:id    会议详情（含参与者、录制列表）
type MeetingManageController struct {
	svc *service.MeetingManageService
}

// NewMeetingManageController Wire Provider
func NewMeetingManageController(svc *service.MeetingManageService) *MeetingManageController {
	return &MeetingManageController{svc: svc}
}

// GetMeetingList GET /api/v1/admin/meetings
func (ctl *MeetingManageController) GetMeetingList(c *gin.Context) {
	ctx := c.Request.Context()

	var req dto.AdminMeetingListRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		utils.ResponseBadRequest(c, "参数格式错误")
		return
	}

	resp, err := ctl.svc.GetMeetingList(ctx, &req)
	if err != nil {
		ctl.handleError(c, err, "获取会议列表失败")
		return
	}
	utils.ResponseOK(c, resp)
}

// GetMeetingDetail GET /api/v1/admin/meetings/:id
func (ctl *MeetingManageController) GetMeetingDetail(c *gin.Context) {
	ctx := c.Request.Context()

	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil || id <= 0 {
		utils.ResponseBadRequest(c, "会议 ID 非法")
		return
	}

	resp, err := ctl.svc.GetMeetingDetail(ctx, id)
	if err != nil {
		ctl.handleError(c, err, "获取会议详情失败")
		return
	}
	utils.ResponseOK(c, resp)
}

// GetMeetingStats GET /api/v1/admin/meetings/stats
func (ctl *MeetingManageController) GetMeetingStats(c *gin.Context) {
	ctx := c.Request.Context()

	resp, err := ctl.svc.GetStats(ctx)
	if err != nil {
		ctl.handleError(c, err, "获取会议统计失败")
		return
	}
	utils.ResponseOK(c, resp)
}

// ForceStopRecording POST /api/v1/admin/meetings/recordings/:id/force-stop
//
// 兼底场景：host 离线/失联未点停止；host 端点击停止后 ffmpeg 异常但 webhook 失效；
// 任何长时间停留在 recording 状态的录制都可由此接口收尾。
//
// 行为：
//   - 终态（ready/failed/uploading）：幂等返回 200
//   - recording 状态：走 media-server stop + MinIO 上传 + DB 状态机
func (ctl *MeetingManageController) ForceStopRecording(c *gin.Context) {
	ctx := c.Request.Context()

	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil || id <= 0 {
		utils.ResponseBadRequest(c, "录制 ID 非法")
		return
	}

	if err := ctl.svc.ForceStopRecording(ctx, id); err != nil {
		ctl.handleError(c, err, "强制结束录制失败")
		return
	}
	utils.ResponseOK(c, gin.H{"recording_id": id, "stopped": true})
}

// handleError 统一业务错误映射
func (ctl *MeetingManageController) handleError(c *gin.Context, err error, fallbackMsg string) {
	switch {
	case errors.Is(err, service.ErrMeetingNotFound),
		errors.Is(err, meetingService.ErrMeetingNotFound),
		errors.Is(err, meetingService.ErrRecordingNotFound):
		utils.ResponseNotFound(c, err.Error())
	case errors.Is(err, meetingService.ErrRecordingNotStoppable):
		utils.ResponseBadRequest(c, err.Error())
	case errors.Is(err, meetingService.ErrMediaServiceUnavailable):
		logs.Warn(c.Request.Context(), "controller.meeting_manage_controller.handleError",
			"媒体服务不可用", zap.Error(err))
		utils.ResponseError(c, "媒体服务暂时不可用，请稍后重试")
	default:
		logs.Warn(c.Request.Context(), "controller.meeting_manage_controller.handleError",
			fallbackMsg, zap.Error(err))
		utils.ResponseError(c, fallbackMsg)
	}
}
