package auth

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"hyapp-admin-server/internal/config"
	"hyapp-admin-server/internal/modules/shared"
	"hyapp-admin-server/internal/repository"
	"hyapp-admin-server/internal/response"
	authcore "hyapp-admin-server/internal/service"
)

const refreshCookieName = "hyapp_admin_refresh"

type Handler struct {
	service *AuthFlowService
	audit   shared.OperationLogger
	cfg     config.Config
}

func New(store *repository.Store, auth *authcore.AuthService, audit shared.OperationLogger, cfg config.Config) *Handler {
	return &Handler{service: NewService(store, auth, cfg), audit: audit, cfg: cfg}
}

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.Login(LoginInput{
		Username:  req.Username,
		Password:  req.Password,
		IP:        c.ClientIP(),
		UserAgent: c.Request.UserAgent(),
	})
	if err != nil {
		response.Unauthorized(c, "用户名或密码错误")
		return
	}

	h.setRefreshCookie(c, result.RefreshToken, int(h.cfg.RefreshTokenTTL.Seconds()))
	response.OK(c, gin.H{
		"accessToken": result.AccessToken,
		"expiresAtMs": result.ExpiresAtMS,
		"user":        shared.UserDTO(result.User),
		"permissions": result.Permissions,
	})
}

func (h *Handler) Logout(c *gin.Context) {
	if token, err := c.Cookie(refreshCookieName); err == nil && token != "" {
		_ = h.service.Logout(token)
	}
	h.setRefreshCookie(c, "", -1)
	response.OK(c, gin.H{"loggedOut": true})
}

func (h *Handler) Refresh(c *gin.Context) {
	token, err := c.Cookie(refreshCookieName)
	if err != nil || token == "" {
		response.Unauthorized(c, "刷新会话不存在")
		return
	}

	result, err := h.service.Refresh(token)
	if err != nil {
		response.Unauthorized(c, "刷新会话已失效")
		return
	}

	response.OK(c, gin.H{
		"accessToken": result.AccessToken,
		"expiresAtMs": result.ExpiresAtMS,
		"user":        shared.UserDTO(result.User),
		"permissions": result.Permissions,
	})
}

func (h *Handler) Me(c *gin.Context) {
	user, permissions, err := h.service.Me(shared.ActorFromContext(c))
	if err != nil {
		response.Unauthorized(c, "用户不存在")
		return
	}

	response.OK(c, gin.H{
		"user":        shared.UserDTO(*user),
		"permissions": permissions,
	})
}

func (h *Handler) ChangePassword(c *gin.Context) {
	var req changePasswordRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "旧密码和新密码不能为空")
		return
	}

	if err := h.service.ChangePassword(shared.ActorFromContext(c), req.OldPassword, req.NewPassword); err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "change-password", "admin_users", "success", "用户修改自己的密码")
	response.OK(c, gin.H{"changed": true})
}

func (h *Handler) setRefreshCookie(c *gin.Context, token string, maxAge int) {
	c.SetSameSite(http.SameSiteLaxMode)
	c.SetCookie(refreshCookieName, token, maxAge, "/api/v1/auth", "", h.cfg.RefreshCookieSecure, true)
}
