// Package auth contains browser-facing authentication and identity routes.
package auth

import (
	"log/slog"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/mailer"
	"github.com/tidbcloud/AgentTeam/internal/sms"
)

func handleAuth(handler api.AuthHandler) gin.HandlerFunc {
	return api.HandleAuth(handler)
}

func handleAuthJSON[T any](handler func(api.AuthenticatedJSON[T]) (api.Response, error)) gin.HandlerFunc {
	return api.HandleAuthJSON[T](handler)
}

// Dependencies contains collaborators and configuration for auth routes.
type Dependencies struct {
	Store                            Store
	AuthFlow                         AuthFlow
	Realtime                         Realtime
	Organizations                    OrganizationProvider
	Mailer                           mailer.Mailer
	MailerProvider                   func() mailer.Mailer
	MobileVerificationSender         sms.Sender
	MobileVerificationSenderProvider func() sms.Sender
	EmailVerificationRequired        bool
	RegistrationPolicy               RegistrationPolicy
	RegistrationPolicyProvider       func() RegistrationPolicy
	VerificationTokenTTL             time.Duration
	SessionTTL                       time.Duration
	PasswordAuthDisabled             bool
	PingCAPAuthConfig                PingCAPAuthConfig
	PingCAPAuthConfigProvider        func() PingCAPAuthConfig
	HTTPClient                       *http.Client
	Logger                           *slog.Logger
}

// RegisterRoutes mounts browser-facing auth and identity routes.
func RegisterRoutes(router gin.IRouter, dependencies Dependencies) {
	if router == nil {
		return
	}
	handlers := newRouteHandlers(dependencies)
	registerAuthRoutes(router.Group("/api/v1/auth"), handlers, dependencies)
	registerMeRoutes(router.Group("/api/v1/me"), handlers, dependencies)
	registerMiniappPairingRoutes(router.Group("/api/v1"), handlers)
}

func registerMiniappPairingRoutes(root gin.IRouter, handlers routeHandlers) {
	root.POST("/miniapp-pairing-exchanges", handlers.miniappPairing.Exchange)
}

func registerAuthRoutes(auth gin.IRouter, handlers routeHandlers, dependencies Dependencies) {
	auth.POST("/login", handlers.sessions.Login)
	auth.POST("/feishu/login-url", handlers.feishu.LoginURL)
	auth.POST("/feishu/login", handlers.feishu.Login)
	auth.POST("/register", handlers.registration.Register)
	auth.POST("/logout", handlers.sessions.Logout)
	auth.POST("/refresh", handlers.sessions.Refresh)
	auth.GET("/mobile/history", api.RequireAuthenticatedUser(dependencies.Store), handleAuth(handlers.mobile.History))
	auth.POST("/mobile/request-verification", api.RequireAuthenticatedUser(dependencies.Store), handleAuthJSON(handlers.mobile.RequestVerification))
	auth.POST("/mobile/verify", api.RequireAuthenticatedUser(dependencies.Store), handleAuthJSON(handlers.mobile.Verify))
	auth.POST("/verify-email", handlers.emailVerification.VerifyEmail)
	auth.POST("/resend-verification", api.RequireAuthenticatedUser(dependencies.Store), handlers.emailVerification.ResendVerification)
	auth.POST("/forgot-password", handlers.emailVerification.ForgotPassword)
	auth.POST("/reset-password", handlers.emailVerification.ResetPassword)
	auth.GET("/invite-info", handlers.invites.Info)
	auth.GET("/pending-invites/:inviteId", handlers.invites.PendingInfo)
	auth.GET(
		"/pending-invites",
		api.RequireAuthenticatedUser(dependencies.Store),
		api.RequireVerifiedIdentity(dependencies.EmailVerificationRequired),
		handleAuth(handlers.invites.Pending),
	)
	auth.POST(
		"/pending-invites/:inviteId/accept",
		api.RequireAuthenticatedUser(dependencies.Store),
		api.RequireVerifiedIdentity(dependencies.EmailVerificationRequired),
		handleAuth(handlers.invites.AcceptPending),
	)
	auth.POST(
		"/pending-invites/:inviteId/dismiss",
		api.RequireAuthenticatedUser(dependencies.Store),
		api.RequireVerifiedIdentity(dependencies.EmailVerificationRequired),
		handleAuth(handlers.invites.DismissPending),
	)
	auth.POST(
		"/accept-invite",
		api.RequireAuthenticatedUser(dependencies.Store),
		api.RequireVerifiedIdentity(dependencies.EmailVerificationRequired),
		handleAuthJSON(handlers.invites.Accept),
	)
	auth.GET("/oidc/discovery", handlers.oidc.Discovery)
	auth.POST("/oidc/authorize-url", handlers.oidc.AuthorizationURL)
	auth.POST("/oidc/callback", handlers.oidc.Callback)
}

func registerMeRoutes(me gin.IRouter, handlers routeHandlers, dependencies Dependencies) {
	me.GET("", api.RequireAuthenticatedUser(dependencies.Store), handleAuth(handlers.profile.Me))
	me.PATCH("", api.RequireAuthenticatedUser(dependencies.Store), handleAuthJSON(handlers.profile.UpdateMe))
	me.GET("/mobile-sessions", api.RequireAuthenticatedUser(dependencies.Store), handleAuth(handlers.mobileSessions.List))
	me.DELETE("/mobile-sessions/:sessionFamilyId", api.RequireAuthenticatedUser(dependencies.Store), handleAuth(handlers.mobileSessions.Revoke))
}
