package projects

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

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

// CronPlanDTO 是计划任务管理响应；MVP 只管理提醒元数据，不执行自主 Agent。
type CronPlanDTO struct {
	ID         string     `json:"id"`
	ProjectID  string     `json:"projectId"`
	Title      string     `json:"title"`
	Schedule   string     `json:"schedule"`
	NextRunAt  *time.Time `json:"nextRunAt"`
	Enabled    bool       `json:"enabled"`
	LastResult string     `json:"lastResult"`
	CreatedAt  time.Time  `json:"createdAt"`
	UpdatedAt  time.Time  `json:"updatedAt"`
}

// CronHandler 单独承载计划任务写接口。
type CronHandler struct {
	service *Service
}

// NewCronHandler 创建计划任务 HTTP registrar。
func NewCronHandler(service *Service) *CronHandler {
	return &CronHandler{service: service}
}

// Register 注册项目内计划任务创建接口。
func (h *CronHandler) Register(router gin.IRouter) {
	router.POST("/projects/:id/cron-plans", h.create)
}

func (h *CronHandler) create(c *gin.Context) {
	userID, project, ok := ownedProjectFromRequest(c)
	if !ok {
		return
	}
	var input struct {
		Title     string `json:"title"`
		Schedule  string `json:"schedule"`
		Enabled   bool   `json:"enabled"`
		NextRunAt string `json:"nextRunAt"`
	}
	if err := c.ShouldBindJSON(&input); err != nil {
		httpx.Error(c, http.StatusBadRequest, "invalid_request", "请求参数无效")
		return
	}
	nextRunAt, err := parseCronOptionalTime(input.NextRunAt)
	if err != nil {
		httpx.Error(c, http.StatusBadRequest, "invalid_request", "下次运行时间格式无效")
		return
	}
	plan, err := h.service.CreateCronPlan(userID, project.ID, CreateCronPlanInput{
		Title: input.Title, Schedule: input.Schedule, Enabled: input.Enabled, NextRunAt: nextRunAt,
	})
	if err != nil {
		writeCronError(c, err)
		return
	}
	c.JSON(http.StatusCreated, cronPlanDTO(*plan))
}

func writeCronError(c *gin.Context, err error) {
	switch {
	case errors.Is(err, ErrCronTitleRequired), errors.Is(err, ErrCronScheduleRequired):
		httpx.Error(c, http.StatusBadRequest, "invalid_request", "计划任务参数无效")
	case errors.Is(err, gorm.ErrRecordNotFound):
		httpx.Error(c, http.StatusNotFound, "not_found", "项目不存在")
	default:
		httpx.Error(c, http.StatusInternalServerError, "internal_error", "计划任务创建失败")
	}
}

func cronPlanDTO(plan models.SenlinAgentCronPlan) CronPlanDTO {
	return CronPlanDTO{
		ID: plan.Identity, ProjectID: plan.ProjectIdentity, Title: plan.Title, Schedule: plan.Schedule,
		NextRunAt: projectUTCOptionalTime(plan.NextRunAt), Enabled: plan.Enabled, LastResult: plan.LastResult,
		CreatedAt: plan.CreatedAt.UTC(), UpdatedAt: plan.UpdatedAt.UTC(),
	}
}

func parseCronOptionalTime(value string) (*time.Time, error) {
	trimmed := strings.TrimSpace(value)
	if trimmed == "" {
		return nil, nil
	}
	parsed, err := time.Parse(time.RFC3339, trimmed)
	if err != nil {
		return nil, err
	}
	parsed = parsed.UTC()
	return &parsed, nil
}

func projectUTCOptionalTime(value *time.Time) *time.Time {
	if value == nil {
		return nil
	}
	result := value.UTC()
	return &result
}
