package providers

import (
	"net/url"
	"strings"
	"time"
)

// AzureProvider encapsulates Azure AD-specific OIDC logic.
type AzureProvider struct {
	*BaseProvider
}

// NewAzureProvider creates a new instance of the AzureProvider.
func NewAzureProvider() *AzureProvider {
	return &AzureProvider{
		BaseProvider: NewBaseProvider(),
	}
}

// GetType returns the provider's type.
func (p *AzureProvider) GetType() ProviderType {
	return ProviderTypeAzure
}

// GetCapabilities returns the specific capabilities of the Azure provider.
func (p *AzureProvider) GetCapabilities() ProviderCapabilities {
	return ProviderCapabilities{
		SupportsRefreshTokens:      true,
		RequiresOfflineAccessScope: true,
		PreferredTokenValidation:   "access",
	}
}

// BuildAuthParams configures Azure-specific authentication parameters.
func (p *AzureProvider) BuildAuthParams(baseParams url.Values, scopes []string) (*AuthParams, error) {
	baseParams.Set("response_mode", "query")

	hasOfflineAccess := false
	for _, scope := range scopes {
		if scope == ScopeOfflineAccess {
			hasOfflineAccess = true
			break
		}
	}
	if !hasOfflineAccess {
		scopes = append(scopes, ScopeOfflineAccess)
	}

	return &AuthParams{
		URLValues: baseParams,
		Scopes:    deduplicateScopes(scopes),
	}, nil
}

// Azure may use access tokens for validation, and this method ensures that behavior is preserved.
func (p *AzureProvider) ValidateTokens(session Session, verifier TokenVerifier, tokenCache TokenCache, refreshGracePeriod time.Duration) (*ValidationResult, error) {
	if !session.GetAuthenticated() {
		if session.GetRefreshToken() != "" {
			return &ValidationResult{NeedsRefresh: true}, nil
		}
		return &ValidationResult{IsExpired: true}, nil
	}

	accessToken := session.GetAccessToken()
	idToken := session.GetIDToken()

	if accessToken != "" {
		if strings.Count(accessToken, ".") == 2 {
			if err := verifier.VerifyToken(accessToken); err != nil {
				if idToken != "" {
					return p.ValidateTokenExpiry(session, idToken, tokenCache, refreshGracePeriod)
				}
				if session.GetRefreshToken() != "" {
					return &ValidationResult{NeedsRefresh: true}, nil
				}
				return &ValidationResult{IsExpired: true}, nil
			}
			return p.ValidateTokenExpiry(session, accessToken, tokenCache, refreshGracePeriod)
		}
		if idToken != "" {
			return p.ValidateTokenExpiry(session, idToken, tokenCache, refreshGracePeriod)
		}
		return &ValidationResult{Authenticated: true}, nil
	}

	if idToken != "" {
		if err := verifier.VerifyToken(idToken); err != nil {
			if session.GetRefreshToken() != "" {
				return &ValidationResult{NeedsRefresh: true}, nil
			}
			return &ValidationResult{IsExpired: true}, nil
		}
		return p.ValidateTokenExpiry(session, idToken, tokenCache, refreshGracePeriod)
	}

	if session.GetRefreshToken() != "" {
		return &ValidationResult{NeedsRefresh: true}, nil
	}
	return &ValidationResult{IsExpired: true}, nil
}

// Azure requires specific tenant configuration and scope handling.
func (p *AzureProvider) ValidateConfig() error {
	return p.BaseProvider.ValidateConfig()
}
