package inbox

import (
	"errors"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"senlinai-agent/backend/internal/httpx"
	"senlinai-agent/backend/internal/logic/auth"
	"senlinai-agent/backend/internal/models"
)

type Handler struct {
	service *Service
}

// InboxItemDTO 隔离 Gorm 自增主键，只通过公开 identity 关联项目和条目。
type InboxItemDTO struct {
	ID         string    `json:"id"`
	ProjectID  string    `json:"projectId"`
	SourceType string    `json:"sourceType"`
	Title      string    `json:"title"`
	Body       string    `json:"body"`
	Status     string    `json:"status"`
	CreatedAt  time.Time `json:"createdAt"`
	UpdatedAt  time.Time `json:"updatedAt"`
}

func NewHandler(service *Service) *Handler {
	return &Handler{service: service}
}

func (h *Handler) Register(router gin.IRouter) {
	router.POST("/projects/:id/inbox", h.capture)
	router.POST("/inbox/:id/analyze", h.analyze)
	router.POST("/inbox/:id/confirm", h.confirm)
}

func (h *Handler) capture(c *gin.Context) {
	userID, ok := currentInboxUser(c)
	if !ok {
		return
	}
	projectIdentity, ok := httpx.IdentityParam(c, "id")
	if !ok {
		return
	}
	var input struct {
		SourceType string `json:"sourceType"`
		Title      string `json:"title"`
		Body       string `json:"body"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		httpx.Error(c, http.StatusBadRequest, "invalid_request", "请求参数无效")
		return
	}
	item, err := h.service.Capture(CaptureInput{
		ProjectIdentity: projectIdentity, UserID: userID, SourceType: input.SourceType, Title: input.Title, Body: input.Body,
	})
	if err != nil {
		writeInboxError(c, err)
		return
	}
	c.JSON(http.StatusCreated, inboxItemDTO(*item))
}

func (h *Handler) analyze(c *gin.Context) {
	userID, ok := currentInboxUser(c)
	if !ok {
		return
	}
	itemIdentity, ok := httpx.IdentityParam(c, "id")
	if !ok {
		return
	}
	suggestions, err := h.service.Analyze(itemIdentity, userID)
	if err != nil {
		writeInboxError(c, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{"suggestions": suggestions})
}

func (h *Handler) confirm(c *gin.Context) {
	userID, ok := currentInboxUser(c)
	if !ok {
		return
	}
	itemIdentity, ok := httpx.IdentityParam(c, "id")
	if !ok {
		return
	}
	var input struct {
		SuggestionIDs []string `json:"suggestionIds"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		httpx.Error(c, http.StatusBadRequest, "invalid_request", "请求参数无效")
		return
	}
	result, err := h.service.Confirm(itemIdentity, userID, input.SuggestionIDs)
	if err != nil {
		writeInboxError(c, err)
		return
	}
	c.JSON(http.StatusOK, result)
}

func currentInboxUser(c *gin.Context) (uint, bool) {
	userID, ok := auth.CurrentUserID(c)
	if !ok {
		httpx.Error(c, http.StatusUnauthorized, "unauthorized", "未登录或登录已失效")
		return 0, false
	}
	return userID, true
}

func inboxItemDTO(item models.SenlinAgentInboxItem) InboxItemDTO {
	return InboxItemDTO{
		ID: item.Identity, ProjectID: item.ProjectIdentity, SourceType: item.SourceType,
		Title: item.Title, Body: item.Body, Status: item.Status,
		CreatedAt: item.CreatedAt.UTC(), UpdatedAt: item.UpdatedAt.UTC(),
	}
}

func writeInboxError(c *gin.Context, err error) {
	switch {
	case errors.Is(err, gorm.ErrRecordNotFound):
		httpx.Error(c, http.StatusNotFound, "not_found", "Inbox 条目或项目不存在")
	case errors.Is(err, ErrInboxAlreadyConfirmed):
		httpx.Error(c, http.StatusConflict, "conflict", "该 Inbox 条目已经确认处理")
	case errors.Is(err, ErrProjectAndUserRequired), errors.Is(err, ErrSourceTypeRequired),
		errors.Is(err, ErrSuggestionSelectionRequired), errors.Is(err, ErrSuggestionNotFound):
		httpx.Error(c, http.StatusBadRequest, "invalid_request", "请求参数或建议选择无效")
	default:
		httpx.Error(c, http.StatusInternalServerError, "internal_error", "Inbox 操作失败，请稍后重试")
	}
}
