package app

import (
	"fmt"
	"time"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/maplefile/client"
	"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/utils"
)

// GetUserProfile fetches the current user's profile
func (a *Application) GetUserProfile() (*client.User, error) {
	// Get API client from auth service
	apiClient := a.authService.GetAPIClient()
	if apiClient == nil {
		return nil, fmt.Errorf("API client not available")
	}

	// Ensure we have a valid session with tokens
	session, err := a.authService.GetCurrentSession(a.ctx)
	if err != nil || session == nil {
		return nil, fmt.Errorf("no active session - please log in")
	}

	if !session.IsValid() {
		return nil, fmt.Errorf("session expired - please log in again")
	}

	// Ensure tokens are set in the API client
	apiClient.SetTokens(session.AccessToken, session.RefreshToken)

	// Fetch user profile from backend
	user, err := apiClient.GetMe(a.ctx)
	if err != nil {
		a.logger.Error("Failed to fetch user profile", zap.Error(err))
		return nil, fmt.Errorf("failed to fetch profile: %w", err)
	}

	a.logger.Info("User profile fetched successfully",
		zap.String("user_id", user.ID),
		zap.String("email", utils.MaskEmail(user.Email)))

	return user, nil
}

// UpdateUserProfile updates the current user's profile
func (a *Application) UpdateUserProfile(input *client.UpdateUserInput) (*client.User, error) {
	// Get API client from auth service
	apiClient := a.authService.GetAPIClient()
	if apiClient == nil {
		return nil, fmt.Errorf("API client not available")
	}

	// Ensure we have a valid session with tokens
	session, err := a.authService.GetCurrentSession(a.ctx)
	if err != nil || session == nil {
		return nil, fmt.Errorf("no active session - please log in")
	}

	if !session.IsValid() {
		return nil, fmt.Errorf("session expired - please log in again")
	}

	// Ensure tokens are set in the API client
	apiClient.SetTokens(session.AccessToken, session.RefreshToken)

	// Update user profile
	user, err := apiClient.UpdateMe(a.ctx, input)
	if err != nil {
		a.logger.Error("Failed to update user profile", zap.Error(err))
		return nil, fmt.Errorf("failed to update profile: %w", err)
	}

	a.logger.Info("User profile updated successfully",
		zap.String("user_id", user.ID),
		zap.String("email", utils.MaskEmail(user.Email)))

	return user, nil
}

// ============================================================================
// Blocked Emails Management
// ============================================================================

// BlockedEmailData represents a blocked email entry for the frontend
type BlockedEmailData struct {
	BlockedEmail string `json:"blocked_email"`
	Reason       string `json:"reason"`
	CreatedAt    string `json:"created_at"`
}

// GetBlockedEmails fetches the list of blocked emails from the backend
func (a *Application) GetBlockedEmails() ([]*BlockedEmailData, error) {
	// Get API client from auth service
	apiClient := a.authService.GetAPIClient()
	if apiClient == nil {
		return nil, fmt.Errorf("API client not available")
	}

	// Ensure we have a valid session with tokens
	session, err := a.authService.GetCurrentSession(a.ctx)
	if err != nil || session == nil {
		return nil, fmt.Errorf("no active session - please log in")
	}

	if !session.IsValid() {
		return nil, fmt.Errorf("session expired - please log in again")
	}

	// Ensure tokens are set in the API client
	apiClient.SetTokens(session.AccessToken, session.RefreshToken)

	// Call backend API
	resp, err := apiClient.ListBlockedEmails(a.ctx)
	if err != nil {
		a.logger.Error("Failed to fetch blocked emails", zap.Error(err))
		return nil, fmt.Errorf("failed to fetch blocked emails: %w", err)
	}

	// Convert to frontend format
	blockedEmails := make([]*BlockedEmailData, 0, len(resp.BlockedEmails))
	for _, blocked := range resp.BlockedEmails {
		blockedEmails = append(blockedEmails, &BlockedEmailData{
			BlockedEmail: blocked.BlockedEmail,
			Reason:       blocked.Reason,
			CreatedAt:    blocked.CreatedAt.Format(time.RFC3339),
		})
	}

	a.logger.Info("Blocked emails fetched successfully",
		zap.Int("count", len(blockedEmails)))

	return blockedEmails, nil
}

// AddBlockedEmail adds an email to the blocked list
func (a *Application) AddBlockedEmail(email, reason string) (*BlockedEmailData, error) {
	// Get API client from auth service
	apiClient := a.authService.GetAPIClient()
	if apiClient == nil {
		return nil, fmt.Errorf("API client not available")
	}

	// Ensure we have a valid session with tokens
	session, err := a.authService.GetCurrentSession(a.ctx)
	if err != nil || session == nil {
		return nil, fmt.Errorf("no active session - please log in")
	}

	if !session.IsValid() {
		return nil, fmt.Errorf("session expired - please log in again")
	}

	// Ensure tokens are set in the API client
	apiClient.SetTokens(session.AccessToken, session.RefreshToken)

	// Call backend API
	blocked, err := apiClient.CreateBlockedEmail(a.ctx, email, reason)
	if err != nil {
		a.logger.Error("Failed to add blocked email",
			zap.String("email", utils.MaskEmail(email)),
			zap.Error(err))
		return nil, fmt.Errorf("failed to block email: %w", err)
	}

	a.logger.Info("Email blocked successfully",
		zap.String("blocked_email", utils.MaskEmail(email)))

	return &BlockedEmailData{
		BlockedEmail: blocked.BlockedEmail,
		Reason:       blocked.Reason,
		CreatedAt:    blocked.CreatedAt.Format(time.RFC3339),
	}, nil
}

// RemoveBlockedEmail removes an email from the blocked list
func (a *Application) RemoveBlockedEmail(email string) error {
	// Get API client from auth service
	apiClient := a.authService.GetAPIClient()
	if apiClient == nil {
		return fmt.Errorf("API client not available")
	}

	// Ensure we have a valid session with tokens
	session, err := a.authService.GetCurrentSession(a.ctx)
	if err != nil || session == nil {
		return fmt.Errorf("no active session - please log in")
	}

	if !session.IsValid() {
		return fmt.Errorf("session expired - please log in again")
	}

	// Ensure tokens are set in the API client
	apiClient.SetTokens(session.AccessToken, session.RefreshToken)

	// Call backend API
	_, err = apiClient.DeleteBlockedEmail(a.ctx, email)
	if err != nil {
		a.logger.Error("Failed to remove blocked email",
			zap.String("email", utils.MaskEmail(email)),
			zap.Error(err))
		return fmt.Errorf("failed to unblock email: %w", err)
	}

	a.logger.Info("Email unblocked successfully",
		zap.String("blocked_email", utils.MaskEmail(email)))

	return nil
}

// ============================================================================
// Account Deletion
// ============================================================================

// DeleteAccount deletes the current user's account
func (a *Application) DeleteAccount(password string) error {
	// Get API client from auth service
	apiClient := a.authService.GetAPIClient()
	if apiClient == nil {
		return fmt.Errorf("API client not available")
	}

	// Ensure we have a valid session with tokens
	session, err := a.authService.GetCurrentSession(a.ctx)
	if err != nil || session == nil {
		return fmt.Errorf("no active session - please log in")
	}

	if !session.IsValid() {
		return fmt.Errorf("session expired - please log in again")
	}

	// Ensure tokens are set in the API client
	apiClient.SetTokens(session.AccessToken, session.RefreshToken)

	// Call backend API to delete account
	err = apiClient.DeleteMe(a.ctx, password)
	if err != nil {
		a.logger.Error("Failed to delete account", zap.Error(err))
		return fmt.Errorf("failed to delete account: %w", err)
	}

	a.logger.Info("Account deleted successfully",
		zap.String("user_id", utils.MaskEmail(session.Email)))

	// Logout after successful deletion
	_ = a.Logout()

	return nil
}
