package handler

import (
	"errors"
	"fmt"
	"kra/internal/biz/system"
	"net/http"
	"strconv"
	"time"

	"kra/internal/service"
	"kra/internal/service/dto"

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

type Version struct{ service *service.VersionService }

func NewVersion(service *service.VersionService) *Version { return &Version{service: service} }

func versionStage(err error) (system.VersionStage, bool) {
	var stageErr *system.VersionStageError
	if !errors.As(err, &stageErr) {
		return "", false
	}
	return stageErr.Stage, true
}

func (h *Version) Delete(c *gin.Context) {
	id, err := positiveUintQuery(c, "ID")
	if err != nil {
		Fail(c, "版本ID非法")
		return
	}
	if err := h.service.DeleteVersions(c.Request.Context(), []uint{id}); err != nil {
		Fail(c, "删除失败:"+err.Error())
		return
	}
	Write(c, CodeSuccess, gin.H{}, "删除成功")
}
func (h *Version) DeleteMany(c *gin.Context) {
	raw := c.QueryArray("IDs[]")
	ids := make([]uint, 0, len(raw))
	for _, value := range raw {
		id, err := positiveUint(value)
		if err != nil {
			Fail(c, "版本ID非法")
			return
		}
		ids = append(ids, id)
	}
	if len(ids) == 0 {
		Fail(c, "版本ID不能为空")
		return
	}
	if err := h.service.DeleteVersions(c.Request.Context(), ids); err != nil {
		Fail(c, "批量删除失败:"+err.Error())
		return
	}
	Write(c, CodeSuccess, gin.H{}, "批量删除成功")
}
func (h *Version) Find(c *gin.Context) {
	id, err := positiveUintQuery(c, "ID")
	if err != nil {
		Fail(c, "版本ID非法")
		return
	}
	item, err := h.service.Version(c.Request.Context(), id)
	if err != nil {
		Fail(c, "查询失败:"+err.Error())
		return
	}
	OKWithData(c, item)
}
func (h *Version) List(c *gin.Context) {
	var req dto.VersionSearchRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		Fail(c, err.Error())
		return
	}
	name, code := "", ""
	if req.VersionName != nil {
		name = *req.VersionName
	}
	if req.VersionCode != nil {
		code = *req.VersionCode
	}
	createdAtRange := make([]*time.Time, 0, len(req.CreatedAtRange))
	for i := range req.CreatedAtRange {
		createdAtRange = append(createdAtRange, &req.CreatedAtRange[i])
	}
	items, total, err := h.service.Versions(c.Request.Context(), req.Page, req.PageSize, name, code, createdAtRange)
	if err != nil {
		Fail(c, "获取失败:"+err.Error())
		return
	}
	Write(c, CodeSuccess, PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
}

func (h *Version) Export(c *gin.Context) {
	var req dto.ExportVersionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err.Error())
		return
	}
	if err := h.service.Export(c.Request.Context(), req.VersionName, req.VersionCode, req.Description, req.MenuIDs, req.APIIDs, req.DictIDs); err != nil {
		switch stage, _ := versionStage(err); stage {
		case system.VersionStageMenus:
			Fail(c, "获取菜单数据失败:"+err.Error())
		case system.VersionStageAPIs:
			Fail(c, "获取API数据失败:"+err.Error())
		case system.VersionStageDictionaries:
			Fail(c, "获取字典数据失败:"+err.Error())
		case system.VersionStageJSON:
			Fail(c, "JSON序列化失败:"+err.Error())
		case system.VersionStageSave:
			Fail(c, "保存版本记录失败:"+err.Error())
		default:
			Fail(c, "创建发版失败:"+err.Error())
		}
		return
	}
	Write(c, CodeSuccess, gin.H{}, "创建发版成功")
}
func (h *Version) Download(c *gin.Context) {
	rawID := c.Query("ID")
	if rawID == "" {
		Fail(c, "版本ID不能为空")
		return
	}
	id, err := positiveUint(rawID)
	if err != nil {
		Fail(c, "版本ID非法")
		return
	}
	raw, code, err := h.service.VersionData(c.Request.Context(), id)
	if err != nil {
		Fail(c, "获取版本记录失败:"+err.Error())
		return
	}
	name := fmt.Sprintf("version_%s_%s.json", code, time.Now().Format("20060102150405"))
	c.Header("Content-Type", "application/json")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name))
	c.Header("Content-Length", strconv.Itoa(len(raw)))
	c.Data(http.StatusOK, "application/json", []byte(raw))
}
func (h *Version) Import(c *gin.Context) {
	var req dto.ImportVersionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, "解析JSON数据失败:"+err.Error())
		return
	}
	if err := h.service.ImportRequest(c.Request.Context(), &req); err != nil {
		if errors.Is(err, system.ErrInvalidVersion) {
			Fail(c, "版本信息格式错误")
			return
		}
		switch stage, _ := versionStage(err); stage {
		case system.VersionStageMenus:
			Fail(c, "导入菜单失败: "+err.Error())
		case system.VersionStageAPIs:
			Fail(c, "导入API失败: "+err.Error())
		case system.VersionStageDictionaries:
			Fail(c, "导入字典失败: "+err.Error())
		default:
			Fail(c, "导入失败:"+err.Error())
		}
		return
	}
	Write(c, CodeSuccess, gin.H{}, "导入成功")
}
