package migration

import (
	"context"
	"fmt"
	"time"

	"golang.org/x/oauth2"

	"github.com/ultisuite/ulti-backend/internal/mail/credentials"
)

// RefreshCredential refreshes an expired migration OAuth token and persists it.
func (s *Service) RefreshCredential(
	ctx context.Context,
	oauth *OAuthService,
	userID, projectID, provider string,
	cred credentials.Credential,
) (credentials.Credential, error) {
	if oauth == nil {
		return cred, fmt.Errorf("migration oauth not configured")
	}
	if !cred.NeedsRefresh() {
		return cred, nil
	}
	if cred.RefreshToken == "" {
		return cred, fmt.Errorf("migration refresh token missing; re-run OAuth consent")
	}
	token, err := oauth.Refresh(ctx, Provider(provider), cred.RefreshToken)
	if err != nil {
		return cred, fmt.Errorf("refresh migration token: %w", err)
	}
	updated := applyOAuthTokenFromOAuth2(cred, token)
	if err := s.SaveCredential(ctx, userID, projectID, provider, updated); err != nil {
		return cred, err
	}
	return updated, nil
}

// SaveCredential encrypts and stores migration OAuth credentials.
func (s *Service) SaveCredential(ctx context.Context, userID, projectID, provider string, cred credentials.Credential) error {
	if s.creds == nil {
		return fmt.Errorf("credential manager not configured")
	}
	cred.AuthType = credentials.AuthOAuth2
	cred.OAuthProvider = provider
	enc, err := s.creds.EncryptCredential(cred)
	if err != nil {
		return err
	}
	var expiresAt *time.Time
	if !cred.Expiry.IsZero() {
		expiresAt = &cred.Expiry
	}
	_, err = s.db.Exec(ctx, `
		UPDATE migration_credentials SET
			encrypted_token = $4,
			expires_at = $5,
			revoked_at = NULL
		WHERE user_id = $1::uuid AND project_id = $2::uuid AND provider = $3
	`, userID, projectID, provider, enc, expiresAt)
	return err
}

func (s *Service) MicrosoftAdminConsentURL(tenant, projectID string) (string, error) {
	if s.oauth == nil {
		return "", fmt.Errorf("migration oauth not configured")
	}
	return s.oauth.AdminConsentURL(tenant, EncodeAdminConsentState(projectID))
}

func applyOAuthTokenFromOAuth2(cred credentials.Credential, token *oauth2.Token) credentials.Credential {
	return applyOAuthToken(cred, &oauthToken{
		AccessToken:  token.AccessToken,
		RefreshToken: token.RefreshToken,
		Expiry:       token.Expiry,
	})
}
