package service

import (
	"context"
	"errors"
	"log"

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

const adminRoleCode = "admin"

type AuthCapabilities struct {
	Password               bool                     `json:"password"`
	EmailActivation        bool                     `json:"email_activation"`
	EmailCode              bool                     `json:"email_code"`
	SMSCode                bool                     `json:"sms_code"`
	PasswordReset          bool                     `json:"password_reset"`
	AdminBootstrapRequired bool                     `json:"admin_bootstrap_required"`
	OAuthProviders         []auth.OAuthProviderInfo `json:"oauth_providers"`
}

func (s *AuthService) SupportsEmailActivation() bool {
	return s != nil && s.emailActivationSvc != nil
}

func (s *AuthService) SupportsEmailCodeLogin() bool {
	return s != nil && s.emailCodeSvc != nil
}

func (s *AuthService) SupportsSMSCodeLogin() bool {
	return s != nil && s.smsCodeSvc != nil
}

func (s *AuthService) GetAuthCapabilities(ctx context.Context) AuthCapabilities {
	if ctx == nil {
		ctx = context.Background()
	}

	return AuthCapabilities{
		Password:               true,
		EmailActivation:        s.SupportsEmailActivation(),
		EmailCode:              s.SupportsEmailCodeLogin(),
		SMSCode:                s.SupportsSMSCodeLogin(),
		AdminBootstrapRequired: s.IsAdminBootstrapRequired(ctx),
		OAuthProviders:         s.GetEnabledOAuthProviders(),
	}
}

func (s *AuthService) IsAdminBootstrapRequired(ctx context.Context) bool {
	if s == nil || s.userRepo == nil || s.roleRepo == nil || s.userRoleRepo == nil {
		return false
	}
	if ctx == nil {
		ctx = context.Background()
	}

	adminRole, err := s.roleRepo.GetByCode(ctx, adminRoleCode)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return true
		}
		log.Printf("auth: resolve auth capabilities failed while loading admin role: %v", err)
		return false
	}

	userIDs, err := s.userRoleRepo.GetUserIDByRoleID(ctx, adminRole.ID)
	if err != nil {
		log.Printf("auth: resolve auth capabilities failed while loading admin users: role_id=%d err=%v", adminRole.ID, err)
		return false
	}
	if len(userIDs) == 0 {
		return true
	}

	hadUnexpectedLookupError := false
	for _, userID := range userIDs {
		user, err := s.userRepo.GetByID(ctx, userID)
		if err != nil {
			if isUserNotFoundError(err) {
				continue
			}
			hadUnexpectedLookupError = true
			log.Printf("auth: resolve auth capabilities failed while loading admin user: user_id=%d err=%v", userID, err)
			continue
		}
		if user != nil && user.Status == domain.UserStatusActive {
			return false
		}
	}

	return !hadUnexpectedLookupError
}
