package handler

import (
	"crypto/subtle"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"

	"github.com/user-management-system/internal/auth"
)

// SSOHandler SSO 处理程序
type SSOHandler struct {
	ssoManager   *auth.SSOManager
	clientsStore auth.SSOClientsStore
}

// NewSSOHandler 创建 SSO 处理程序
func NewSSOHandler(ssoManager *auth.SSOManager, clientsStore auth.SSOClientsStore) *SSOHandler {
	return &SSOHandler{
		ssoManager:   ssoManager,
		clientsStore: clientsStore,
	}
}

// AuthorizeRequest 授权请求
type AuthorizeRequest struct {
	ClientID     string `form:"client_id" binding:"required"`
	RedirectURI  string `form:"redirect_uri" binding:"required"`
	ResponseType string `form:"response_type" binding:"required"`
	Scope        string `form:"scope"`
	State        string `form:"state"`
}

// Authorize 处理 SSO 授权请求
// @Summary SSO 授权
// @Description 处理 SSO 授权请求，返回授权码或访问令牌
// @Tags SSO
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param client_id query string true "客户端ID"
// @Param redirect_uri query string true "回调地址"
// @Param response_type query string true "响应类型" Enums(code, token)
// @Param scope query string false "授权范围"
// @Param state query string false "状态参数"
// @Success 302 {string} string "重定向到回调地址"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/authorize [get]
func (h *SSOHandler) Authorize(c *gin.Context) {
	var req AuthorizeRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	// 验证 response_type
	if req.ResponseType != "code" && req.ResponseType != "token" {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "unsupported response_type"})
		return
	}

	// 验证 redirect_uri 是否在白名单中
	if h.clientsStore != nil {
		if !h.clientsStore.ValidateClientRedirectURI(req.ClientID, req.RedirectURI) {
			c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "invalid redirect_uri"})
			return
		}
	}

	// 获取当前登录用户（从 auth middleware 设置的 context）
	userID, ok := getUserIDFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	username, ok := getUsernameFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	// 生成授权码或 access token
	if req.ResponseType == "code" {
		code, err := h.ssoManager.GenerateAuthorizationCode(
			req.ClientID,
			req.RedirectURI,
			req.Scope,
			userID,
			username,
		)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "failed to generate code"})
			return
		}

		// 重定向回客户端
		redirectURL := req.RedirectURI + "?code=" + code
		if req.State != "" {
			redirectURL += "&state=" + req.State
		}
		c.Redirect(http.StatusFound, redirectURL)
	} else {
		// implicit 模式，直接返回 token
		code, err := h.ssoManager.GenerateAuthorizationCode(
			req.ClientID,
			req.RedirectURI,
			req.Scope,
			userID,
			username,
		)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "failed to generate code"})
			return
		}

		// 验证授权码获取 session
		session, err := h.ssoManager.ValidateAuthorizationCode(code)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "failed to validate code"})
			return
		}

		token, _, err := h.ssoManager.GenerateAccessToken(req.ClientID, session)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "failed to generate token"})
			return
		}

		// 重定向回客户端，带 token
		redirectURL := req.RedirectURI + "#access_token=" + token + "&expires_in=7200"
		if req.State != "" {
			redirectURL += "&state=" + req.State
		}
		c.Redirect(http.StatusFound, redirectURL)
	}
}

// TokenRequest Token 请求
type TokenRequest struct {
	GrantType    string `form:"grant_type" binding:"required"`
	Code         string `form:"code"`
	RedirectURI  string `form:"redirect_uri"`
	ClientID     string `form:"client_id" binding:"required"`
	ClientSecret string `form:"client_secret" binding:"required"`
}

// TokenResponse Token 响应
type TokenResponse struct {
	AccessToken string `json:"access_token"`
	TokenType   string `json:"token_type"`
	ExpiresIn   int64  `json:"expires_in"`
	Scope       string `json:"scope"`
}

// Token 处理 Token 请求
// @Summary 获取 Access Token
// @Description 使用授权码获取 Access Token（授权码模式第二步）
// @Tags SSO
// @Accept json
// @Produce json
// @Param grant_type formData string true "授权类型" Enums(authorization_code)
// @Param code formData string false "授权码"
// @Param redirect_uri formData string false "回调地址"
// @Param client_id formData string true "客户端ID"
// @Param client_secret formData string true "客户端密钥"
// @Success 200 {object} TokenResponse "访问令牌响应"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "客户端认证失败"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/token [post]
func (h *SSOHandler) Token(c *gin.Context) {
	var req TokenRequest
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	// 验证 grant_type
	if req.GrantType != "authorization_code" {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "unsupported grant_type"})
		return
	}

	// 验证客户端凭证
	if h.clientsStore != nil {
		client, err := h.clientsStore.GetByClientID(req.ClientID)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "invalid client"})
			return
		}
		// 使用常量时间比较防止时序攻击
		if subtle.ConstantTimeCompare([]byte(req.ClientSecret), []byte(client.ClientSecret)) != 1 {
			c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "invalid client_secret"})
			return
		}
	}

	// 验证授权码
	session, err := h.ssoManager.ValidateAuthorizationCode(req.Code)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "invalid code"})
		return
	}

	// 生成 access token
	token, expiresAt, err := h.ssoManager.GenerateAccessToken(req.ClientID, session)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "failed to generate token"})
		return
	}

	c.JSON(http.StatusOK, TokenResponse{
		AccessToken: token,
		TokenType:   "Bearer",
		ExpiresIn:   int64(time.Until(expiresAt).Seconds()),
		Scope:       session.Scope,
	})
}

// IntrospectRequest Introspect 请求
type IntrospectRequest struct {
	Token    string `form:"token" binding:"required"`
	ClientID string `form:"client_id"`
}

// IntrospectResponse Introspect 响应
type IntrospectResponse struct {
	Active    bool   `json:"active"`
	UserID    int64  `json:"user_id,omitempty"`
	Username  string `json:"username,omitempty"`
	ExpiresAt int64  `json:"exp,omitempty"`
	Scope     string `json:"scope,omitempty"`
}

// Introspect 验证 access token
// @Summary 验证 Access Token
// @Description 验证 Access Token 的有效性并返回相关信息
// @Tags SSO
// @Accept json
// @Produce json
// @Param token formData string true "Access Token"
// @Param client_id formData string false "客户端ID"
// @Success 200 {object} IntrospectResponse "Token信息"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/introspect [post]
func (h *SSOHandler) Introspect(c *gin.Context) {
	var req IntrospectRequest
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	info, err := h.ssoManager.IntrospectToken(req.Token)
	if err != nil {
		c.JSON(http.StatusOK, IntrospectResponse{Active: false})
		return
	}

	c.JSON(http.StatusOK, IntrospectResponse{
		Active:    info.Active,
		UserID:    info.UserID,
		Username:  info.Username,
		ExpiresAt: info.ExpiresAt.Unix(),
		Scope:     info.Scope,
	})
}

// RevokeRequest 撤销请求
type RevokeRequest struct {
	Token string `form:"token" binding:"required"`
}

// Revoke 撤销 access token
// @Summary 撤销 Access Token
// @Description 撤销指定的 Access Token
// @Tags SSO
// @Accept json
// @Produce json
// @Param token formData string true "Access Token"
// @Success 200 {object} Response "撤销成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/revoke [post]
func (h *SSOHandler) Revoke(c *gin.Context) {
	var req RevokeRequest
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
		return
	}

	h.ssoManager.RevokeToken(req.Token)

	c.JSON(http.StatusOK, gin.H{"code": 0, "message": "token revoked"})
}

// UserInfoResponse 用户信息响应
type UserInfoResponse struct {
	UserID   int64  `json:"user_id"`
	Username string `json:"username"`
}

// UserInfo 获取当前用户信息
// @Summary 获取 SSO 用户信息
// @Description 获取当前通过 SSO 授权的用户信息
// @Tags SSO
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=UserInfoResponse} "用户信息"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/userinfo [get]
func (h *SSOHandler) UserInfo(c *gin.Context) {
	userID, ok := getUserIDFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	username, ok := getUsernameFromContext(c)
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "message": "unauthorized"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "success",
		"data": UserInfoResponse{
			UserID:   userID,
			Username: username,
		},
	})
}
