package auth

import (
	"log/slog"

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

type routeHandlers struct {
	sessions          *SessionHandler
	profile           *ProfileHandler
	registration      *RegistrationHandler
	emailVerification *EmailVerificationHandler
	invites           *InviteHandler
	mobile            *MobileHandler
	feishu            *FeishuHandler
	oidc              *OIDCHandler
	miniappPairing    *MiniappPairingHandler
	mobileSessions    *MobileSessionHandler
}

func newRouteHandlers(dependencies Dependencies) routeHandlers {
	logger := dependencies.Logger
	if logger == nil {
		logger = slog.Default().With(slog.String("domain", "auth"))
	}
	return routeHandlers{
		sessions: &SessionHandler{
			logger:                    logger,
			store:                     dependencies.Store,
			authFlow:                  dependencies.AuthFlow,
			emailVerificationRequired: dependencies.EmailVerificationRequired,
			sessionTTL:                dependencies.SessionTTL,
			passwordAuthDisabled:      dependencies.PasswordAuthDisabled,
		},
		profile: &ProfileHandler{
			store:                dependencies.Store,
			passwordAuthDisabled: dependencies.PasswordAuthDisabled,
		},
		registration: &RegistrationHandler{
			logger:                     logger,
			store:                      dependencies.Store,
			authFlow:                   dependencies.AuthFlow,
			mailerProvider:             mailerProviderFromDependencies(dependencies),
			emailVerificationRequired:  dependencies.EmailVerificationRequired,
			registrationPolicyProvider: registrationPolicyProviderFromDependencies(dependencies),
			verificationTokenTTL:       dependencies.VerificationTokenTTL,
			sessionTTL:                 dependencies.SessionTTL,
			passwordAuthDisabled:       dependencies.PasswordAuthDisabled,
		},
		emailVerification: &EmailVerificationHandler{
			logger:                    logger,
			store:                     dependencies.Store,
			mailerProvider:            mailerProviderFromDependencies(dependencies),
			emailVerificationRequired: dependencies.EmailVerificationRequired,
			verificationTokenTTL:      dependencies.VerificationTokenTTL,
			passwordAuthDisabled:      dependencies.PasswordAuthDisabled,
		},
		invites: &InviteHandler{
			authFlow: dependencies.AuthFlow,
			realtime: dependencies.Realtime,
		},
		mobile: &MobileHandler{
			logger:                           logger,
			store:                            dependencies.Store,
			mobileVerificationSenderProvider: mobileVerificationSenderProviderFromDependencies(dependencies),
			passwordAuthDisabled:             dependencies.PasswordAuthDisabled,
		},
		feishu: &FeishuHandler{
			store:         dependencies.Store,
			authFlow:      dependencies.AuthFlow,
			organizations: dependencies.Organizations,
			sessionTTL:    dependencies.SessionTTL,
		},
		oidc: &OIDCHandler{
			store:                     dependencies.Store,
			authFlow:                  dependencies.AuthFlow,
			logger:                    logger,
			sessionTTL:                dependencies.SessionTTL,
			pingCAPAuthConfigProvider: pingCAPAuthConfigProviderFromDependencies(dependencies),
			httpClient:                dependencies.HTTPClient,
		},
		miniappPairing: &MiniappPairingHandler{
			store:      dependencies.Store,
			sessionTTL: dependencies.SessionTTL,
		},
		mobileSessions: &MobileSessionHandler{store: dependencies.Store},
	}
}

func mailerProviderFromDependencies(dependencies Dependencies) func() mailer.Mailer {
	if dependencies.MailerProvider != nil {
		return dependencies.MailerProvider
	}
	staticMailer := dependencies.Mailer
	return func() mailer.Mailer { return staticMailer }
}

func mobileVerificationSenderProviderFromDependencies(dependencies Dependencies) func() sms.Sender {
	if dependencies.MobileVerificationSenderProvider != nil {
		return dependencies.MobileVerificationSenderProvider
	}
	staticSender := dependencies.MobileVerificationSender
	if staticSender == nil {
		staticSender = sms.NewNoop(dependencies.Logger)
	}
	return func() sms.Sender { return staticSender }
}

func registrationPolicyProviderFromDependencies(dependencies Dependencies) func() RegistrationPolicy {
	if dependencies.RegistrationPolicyProvider != nil {
		return dependencies.RegistrationPolicyProvider
	}
	staticPolicy := dependencies.RegistrationPolicy
	if staticPolicy.IsZero() {
		staticPolicy = NewRegistrationPolicy(RegistrationModeOpen, nil)
	}
	return func() RegistrationPolicy { return staticPolicy }
}

func pingCAPAuthConfigProviderFromDependencies(dependencies Dependencies) func() PingCAPAuthConfig {
	if dependencies.PingCAPAuthConfigProvider != nil {
		return dependencies.PingCAPAuthConfigProvider
	}
	staticConfig := dependencies.PingCAPAuthConfig
	return func() PingCAPAuthConfig { return staticConfig }
}
