package handler

import (
	"fmt"
	"kra/internal/service"
	"kra/internal/service/dto"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

type Task struct {
	service *service.TaskService
}

func NewTask(service *service.TaskService) *Task {
	return &Task{service: service}
}

func (h *Task) Create(c *gin.Context) {
	var req dto.TaskRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err.Error())
		return
	}
	_, err := h.service.CreateRequest(c.Request.Context(), &req)
	if err != nil {
		Fail(c, "创建失败: "+err.Error())
		return
	}
	Write(c, CodeSuccess, gin.H{}, "创建成功")
}

func (h *Task) Update(c *gin.Context) {
	var req dto.TaskRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err.Error())
		return
	}
	if err := h.service.UpdateRequest(c.Request.Context(), &req); err != nil {
		Fail(c, "更新失败: "+err.Error())
		return
	}
	Write(c, CodeSuccess, gin.H{}, "更新成功")
}

func (h *Task) Delete(c *gin.Context) {
	var req dto.DeleteTaskRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err.Error())
		return
	}
	if err := h.service.Delete(c.Request.Context(), req.ID); err != nil {
		Fail(c, "删除失败")
		return
	}
	Write(c, CodeSuccess, gin.H{}, "删除成功")
}

func (h *Task) Toggle(c *gin.Context) {
	var req dto.ToggleTaskRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err.Error())
		return
	}
	if err := h.service.Toggle(c.Request.Context(), req.ID, req.Enabled); err != nil {
		Fail(c, "操作失败: "+err.Error())
		return
	}
	Write(c, CodeSuccess, gin.H{}, "操作成功")
}

func (h *Task) Trigger(c *gin.Context) {
	var req dto.DeleteTaskRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err.Error())
		return
	}
	if err := h.service.Trigger(c.Request.Context(), req.ID); err != nil {
		Fail(c, "触发失败: "+err.Error())
		return
	}
	Write(c, CodeSuccess, gin.H{}, "已触发, 执行结果见执行日志")
}

func (h *Task) List(c *gin.Context) {
	var req dto.TaskListRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		Fail(c, err.Error())
		return
	}
	items, total, err := h.service.ListRequest(c.Request.Context(), req.Page, req.PageSize, req.Name, req.ExecutorType, req.Enabled)
	if err != nil {
		Fail(c, "获取失败")
		return
	}
	Write(c, CodeSuccess, PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
}

func (h *Task) Logs(c *gin.Context) {
	var req dto.TaskLogListRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		Fail(c, err.Error())
		return
	}
	items, total, err := h.service.Logs(c.Request.Context(), req.Page, req.PageSize, req.TaskID, req.Status)
	if err != nil {
		Fail(c, "获取失败")
		return
	}
	Write(c, CodeSuccess, PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
}

func (h *Task) Methods(c *gin.Context) {
	Write(c, CodeSuccess, gin.H{"methods": h.service.RegisteredMethods()}, "获取成功")
}

func (h *Task) AlertStream(c *gin.Context) {
	claims := Claims(c)
	if claims == nil || claims.ID == 0 {
		Fail(c, "未获取到用户身份")
		return
	}
	c.Header("Content-Type", "text/event-stream; charset=utf-8")
	c.Header("Cache-Control", "no-cache, no-transform")
	c.Header("Connection", "keep-alive")
	c.Header("X-Accel-Buffering", "no")
	flusher, ok := c.Writer.(http.Flusher)
	if !ok {
		Fail(c, "SSE 不受支持")
		return
	}
	// Remove the normal server deadline for long-lived SSE connections.
	controller := http.NewResponseController(c.Writer)
	_ = controller.SetWriteDeadline(time.Time{})
	_ = controller.SetReadDeadline(time.Time{})
	events := h.service.Subscribe(claims.ID)
	defer h.service.Unsubscribe(claims.ID, events)
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()
	_, _ = fmt.Fprint(c.Writer, ": connected\n\n")
	flusher.Flush()
	for {
		select {
		case event, open := <-events:
			if !open {
				return
			}
			_, _ = fmt.Fprintf(c.Writer, "event: timedTask:alert\ndata: %s\n\n", event)
			flusher.Flush()
		case <-ticker.C:
			_, _ = fmt.Fprint(c.Writer, ": ping\n\n")
			flusher.Flush()
		case <-c.Request.Context().Done():
			return
		}
	}
}
