package auth

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

	"hfb_sys/backend/pkg/response"

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

type Handler struct {
	service *Service
}

type SendSMSRequest struct {
	Phone       string `json:"phone" binding:"required"`
	CaptchaID   string `json:"captcha_id" binding:"required"`
	CaptchaCode string `json:"captcha_code" binding:"required"`
}

type LoginRequest struct {
	Phone string `json:"phone" binding:"required"`
	Code  string `json:"code" binding:"required,len=6"`
}

type RefreshRequest struct {
	RefreshToken string `json:"refresh_token" binding:"required"`
}

type PasswordLoginRequest struct {
	Phone    string `json:"phone" binding:"required"`
	Password string `json:"password" binding:"required,min=8,max=20"`
}

type SetPasswordRequest struct {
	Password    string `json:"password" binding:"required,min=8,max=20"`
	OldPassword string `json:"old_password"`
}

type RegisterRequest struct {
	Phone    string `json:"phone" binding:"required"`
	Code     string `json:"code" binding:"required,len=6"`
	Password string `json:"password" binding:"required,min=8,max=20"`
}

type ResetPasswordRequest struct {
	Phone       string `json:"phone" binding:"required"`
	Code        string `json:"code" binding:"required,len=6"`
	NewPassword string `json:"new_password" binding:"required,min=8,max=20"`
}

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

func (h *Handler) Captcha(c *gin.Context) {
	item, err := h.service.Captcha(c.Request.Context())
	if err != nil {
		writeAuthError(c, err)
		return
	}
	response.OK(c, item)
}

// SendSMS 发送短信验证码
// @Summary      发送短信验证码
// @Description  发送登录验证码到指定手机号
// @Tags         认证
// @Accept       json
// @Produce      json
// @Param        request body SendSMSRequest true "手机号"
// @Success      200 {object} response.Body "发送成功"
// @Failure      400 {object} response.Body "请求参数错误"
// @Failure      500 {object} response.Body "服务器错误"
// @Router       /auth/sms/send [post]
func (h *Handler) SendSMS(c *gin.Context) {
	var req SendSMSRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "手机号和图形验证码不能为空")
		return
	}
	if err := h.service.SendSMSCode(c.Request.Context(), strings.TrimSpace(req.Phone), strings.TrimSpace(req.CaptchaID), strings.TrimSpace(req.CaptchaCode)); err != nil {
		writeAuthError(c, err)
		return
	}
	response.OK(c, gin.H{"phone": PublicPhone(req.Phone), "expires_in": 300})
}

// Login 短信验证码登录
// @Summary      短信验证码登录
// @Description  使用手机号和验证码登录
// @Tags         认证
// @Accept       json
// @Produce      json
// @Param        request body LoginRequest true "登录信息"
// @Success      200 {object} response.Body "登录成功，返回用户信息和 token"
// @Failure      400 {object} response.Body "请求参数错误"
// @Failure      401 {object} response.Body "验证码错误"
// @Failure      500 {object} response.Body "服务器错误"
// @Router       /auth/sms/login [post]
func (h *Handler) Login(c *gin.Context) {
	var req LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "手机号和验证码不能为空")
		return
	}
	result, err := h.service.LoginWithSMS(c.Request.Context(), strings.TrimSpace(req.Phone), strings.TrimSpace(req.Code))
	if err != nil {
		writeAuthError(c, err)
		return
	}
	response.OK(c, result)
}

// Refresh 刷新访问令牌
// @Summary      刷新访问令牌
// @Description  使用 refresh_token 获取新的 access_token
// @Tags         认证
// @Accept       json
// @Produce      json
// @Param        request body RefreshRequest true "刷新令牌"
// @Success      200 {object} response.Body "刷新成功，返回新的 token"
// @Failure      400 {object} response.Body "请求参数错误"
// @Failure      401 {object} response.Body "refresh_token 无效"
// @Router       /auth/refresh [post]
func (h *Handler) Refresh(c *gin.Context) {
	var req RefreshRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "refresh_token 不能为空")
		return
	}
	tokens, err := h.service.RefreshToken(req.RefreshToken)
	if err != nil {
		response.Unauthorized(c, "刷新令牌无效或已过期")
		return
	}
	response.OK(c, tokens)
}

// Logout 登出
// @Summary      登出
// @Description  用户登出（客户端需清除本地 token）
// @Tags         认证
// @Accept       json
// @Produce      json
// @Success      200 {object} response.Body "登出成功"
// @Security     BearerAuth
// @Router       /auth/logout [post]
func (h *Handler) Logout(c *gin.Context) {
	response.OK(c, gin.H{"logged_out": true})
}

func (h *Handler) PasswordLogin(c *gin.Context) {
	var req PasswordLoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "手机号和密码不能为空，密码长度 8-20 位")
		return
	}
	result, err := h.service.LoginWithPassword(c.Request.Context(), strings.TrimSpace(req.Phone), req.Password, c.ClientIP())
	if err != nil {
		writeAuthError(c, err)
		return
	}
	response.OK(c, result)
}

func (h *Handler) Register(c *gin.Context) {
	var req RegisterRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "手机号、验证码和密码不能为空，密码长度 8-20 位")
		return
	}
	result, err := h.service.RegisterWithPassword(c.Request.Context(), strings.TrimSpace(req.Phone), strings.TrimSpace(req.Code), req.Password)
	if err != nil {
		writeAuthError(c, err)
		return
	}
	response.OK(c, result)
}

func (h *Handler) SetPassword(c *gin.Context) {
	var req SetPasswordRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "密码不能为空，长度 8-20 位")
		return
	}
	userID, ok := currentUserID(c)
	if !ok {
		response.Unauthorized(c, "缺少用户上下文")
		return
	}
	if err := h.service.SetPassword(c.Request.Context(), userID, req.Password, req.OldPassword); err != nil {
		writeAuthError(c, err)
		return
	}
	response.OK(c, gin.H{"updated": true})
}

func (h *Handler) ResetPassword(c *gin.Context) {
	var req ResetPasswordRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "手机号、验证码和新密码不能为空")
		return
	}
	if err := h.service.ResetPassword(c.Request.Context(), strings.TrimSpace(req.Phone), strings.TrimSpace(req.Code), req.NewPassword); err != nil {
		writeAuthError(c, err)
		return
	}
	response.OK(c, gin.H{"reseted": true})
}

func writeAuthError(c *gin.Context, err error) {
	switch {
	case errors.Is(err, ErrDependencyUnavailable):
		response.ServiceUnavailable(c, "数据库或 Redis 未连接")
	case errors.Is(err, ErrInvalidPhone):
		response.BadRequest(c, "手机号格式不正确")
	case errors.Is(err, ErrCaptchaInvalid):
		response.BadRequest(c, "图形验证码错误或已过期")
	case errors.Is(err, ErrCodeRateLimited):
		response.Error(c, http.StatusTooManyRequests, "rate_limited", "验证码发送过于频繁")
	case errors.Is(err, ErrSMSSendFailed):
		response.Error(c, http.StatusBadGateway, "sms_send_failed", "验证码发送失败，请稍后重试")
	case errors.Is(err, ErrCodeInvalid):
		response.BadRequest(c, "验证码错误或已过期")
	case errors.Is(err, ErrUserDisabled):
		response.Error(c, http.StatusForbidden, "user_disabled", "用户已被冻结")
	case errors.Is(err, ErrInvalidPassword):
		response.BadRequest(c, "手机号或密码错误")
	case errors.Is(err, ErrInvalidOldPassword):
		response.BadRequest(c, "原密码错误")
	case errors.Is(err, ErrPasswordNotSet):
		response.BadRequest(c, "未设置密码，请使用短信验证码登录后设置密码")
	case errors.Is(err, ErrPasswordTooWeak):
		response.BadRequest(c, "密码长度应为 8-20 位")
	case errors.Is(err, ErrLoginLocked):
		response.Error(c, http.StatusTooManyRequests, "login_locked", "登录失败次数过多，请 15 分钟后再试")
	case errors.Is(err, ErrUserAlreadyExists):
		response.BadRequest(c, "该手机号已注册，请直接登录或使用短信验证码登录")
	default:
		response.Error(c, http.StatusInternalServerError, "internal_error", "服务暂时不可用")
	}
}

func currentUserID(c *gin.Context) (uint64, bool) {
	val, exists := c.Get("user_id")
	if !exists {
		return 0, false
	}
	userID, ok := val.(uint64)
	return userID, ok
}
