package handler

import (
	"strconv"
	"time"

	"kra/internal/modules/system/dto"
	"kra/internal/modules/system/service"
	"kra/internal/modules/system/transport/httpx"
	"kra/internal/modules/system/transport/middleware"

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

type User struct {
	service *service.UserService
	auth    *service.AuthService
}

func NewUser(user *service.UserService, auth *service.AuthService) *User {
	return &User{service: user, auth: auth}
}

func (h *User) List(c *gin.Context) {
	var req dto.UserListRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if req.Page == 0 {
		httpx.Fail(c, "Page值不能为空")
		return
	}
	if req.PageSize == 0 {
		httpx.Fail(c, "PageSize值不能为空")
		return
	}
	items, total, err := h.service.ListUsersRequest(c.Request.Context(), &req)
	if err != nil {
		httpx.Fail(c, "获取失败")
		return
	}
	httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
}

func (h *User) Create(c *gin.Context) {
	var req dto.UserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if req.Username == "" {
		httpx.Fail(c, "Username值不能为空")
		return
	}
	if req.Password == "" {
		httpx.Fail(c, "Password值不能为空")
		return
	}
	if req.NickName == "" {
		httpx.Fail(c, "NickName值不能为空")
		return
	}
	if req.AuthorityID == 0 {
		httpx.Fail(c, "AuthorityId值不能为空")
		return
	}
	result, err := h.service.CreateUserRequest(c.Request.Context(), &req)
	if err != nil {
		if service.IsPasswordPolicyError(err) {
			httpx.Fail(c, err.Error())
			return
		}
		if result == nil {
			result = &dto.UserResponse{}
		}
		httpx.Write(c, httpx.CodeError, gin.H{"user": result}, "注册失败")
		return
	}
	httpx.Write(c, httpx.CodeSuccess, gin.H{"user": result}, "注册成功")
}

func (h *User) Update(c *gin.Context) {
	var req dto.UserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if req.ID == 0 {
		httpx.Fail(c, "ID值不能为空")
		return
	}
	if err := h.service.UpdateUserRequest(c.Request.Context(), &req); err != nil {
		httpx.Fail(c, "修改失败")
		return
	}
	httpx.Write(c, httpx.CodeSuccess, gin.H{}, "设置成功")
}

func (h *User) UpdateSelf(c *gin.Context) {
	claims := middleware.Claims(c)
	if claims == nil {
		httpx.NoAuth(c, "未登录或非法访问")
		return
	}
	var req dto.SelfUserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if err := h.service.UpdateSelfUserRequest(c.Request.Context(), claims.ID, &req); err != nil {
		httpx.Fail(c, "修改失败")
		return
	}
	httpx.Write(c, httpx.CodeSuccess, gin.H{}, "设置成功")
}

func (h *User) Delete(c *gin.Context) {
	var req dto.IDRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if req.ID == 0 {
		httpx.Fail(c, "ID值不能为空")
		return
	}
	claims := middleware.Claims(c)
	if claims != nil && claims.ID == req.ID {
		httpx.Fail(c, "删除失败, 无法删除自己。")
		return
	}
	if err := h.service.DeleteUser(c.Request.Context(), req.ID); err != nil {
		httpx.Fail(c, "删除失败")
		return
	}
	httpx.Write(c, httpx.CodeSuccess, gin.H{}, "删除成功")
}

func (h *User) ResetPassword(c *gin.Context) {
	var req dto.ResetPasswordRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if err := h.service.ResetPassword(c.Request.Context(), req.ID, req.Password); err != nil {
		if service.IsPasswordPolicyError(err) {
			httpx.Fail(c, err.Error())
			return
		}
		httpx.Fail(c, "重置失败"+err.Error())
		return
	}
	httpx.Write(c, httpx.CodeSuccess, gin.H{}, "重置成功")
}

func (h *User) ChangePassword(c *gin.Context) {
	claims := middleware.Claims(c)
	var req dto.ChangePasswordRequest
	if claims == nil {
		httpx.NoAuth(c, "未登录或非法访问")
		return
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if req.Password == "" {
		httpx.Fail(c, "Password值不能为空")
		return
	}
	if req.NewPassword == "" {
		httpx.Fail(c, "NewPassword值不能为空")
		return
	}
	if err := h.service.ChangePassword(c.Request.Context(), claims.ID, req.Password, req.NewPassword); err != nil {
		if service.IsPasswordPolicyError(err) {
			httpx.Fail(c, err.Error())
			return
		}
		httpx.Fail(c, "修改失败，原密码与当前账户不符")
		return
	}
	httpx.Write(c, httpx.CodeSuccess, gin.H{}, "修改成功")
}

func (h *User) SetSelfSetting(c *gin.Context) {
	claims := middleware.Claims(c)
	var setting map[string]any
	if claims == nil {
		httpx.NoAuth(c, "未登录或非法访问")
		return
	}
	if err := c.ShouldBindJSON(&setting); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if err := h.service.SetUserSetting(c.Request.Context(), claims.ID, setting); err != nil {
		httpx.Fail(c, "设置失败")
		return
	}
	httpx.Write(c, httpx.CodeSuccess, gin.H{}, "设置成功")
}

func (h *User) SetAuthorities(c *gin.Context) {
	var req dto.UserAuthoritiesRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if err := h.service.SetUserAuthorities(c.Request.Context(), req.ID, req.AuthorityIDs); err != nil {
		httpx.Fail(c, "修改失败")
		return
	}
	httpx.Write(c, httpx.CodeSuccess, gin.H{}, "修改成功")
}

func (h *User) SwitchAuthority(c *gin.Context) {
	claims := middleware.Claims(c)
	var req dto.SwitchAuthorityRequest
	if claims == nil {
		httpx.NoAuth(c, "未登录或非法访问")
		return
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	if req.AuthorityID == 0 {
		httpx.Fail(c, "AuthorityId值不能为空")
		return
	}
	login, err := h.auth.SwitchAuthority(c.Request.Context(), claims, req.AuthorityID)
	if err != nil {
		httpx.Fail(c, err.Error())
		return
	}
	c.Header("new-token", login.Token)
	c.Header("new-expires-at", strconv.FormatInt(login.ExpiresAt/1000, 10))
	maxAge := int(time.UnixMilli(login.ExpiresAt).Unix() - time.Now().Unix())
	httpx.SetTokenCookie(c, login.Token, maxAge)
	httpx.Write(c, httpx.CodeSuccess, gin.H{}, "修改成功")
}

func (h *User) Get(c *gin.Context) {
	claims := middleware.Claims(c)
	if claims == nil {
		httpx.NoAuth(c, "未登录或非法访问")
		return
	}
	result, err := h.service.UserByUUID(c.Request.Context(), claims.UUID)
	if err != nil {
		httpx.Fail(c, "获取失败")
		return
	}
	httpx.Write(c, httpx.CodeSuccess, gin.H{"userInfo": result}, "获取成功")
}
