package service

import (
	"context"
	"sno/internal/models"
	"sno/internal/repository"
	"sort"
)

// UserService defines the interface for user-related business logic.
type UserService interface {
	GetUserProfile(ctx context.Context, userID int64) (*models.User, error)
	GetOrCreateUser(ctx context.Context, telegramID int64, firstName, lastName, username, photoURL string) (*models.User, error)
	GetUserPurchases(ctx context.Context, userID int64) ([]models.Purchase, error)
	GetUserTransactions(ctx context.Context, userID int64) ([]models.Transaction, error)
}

// userService implements the UserService interface.
type userService struct {
	userRepo        repository.UserRepository
	purchaseRepo    repository.PurchaseRepository
	quizAttemptRepo repository.QuizAttemptRepository
}

// NewUserService creates a new instance of a user service.
func NewUserService(userRepo repository.UserRepository, purchaseRepo repository.PurchaseRepository, quizAttemptRepo repository.QuizAttemptRepository) UserService {
	return &userService{userRepo: userRepo, purchaseRepo: purchaseRepo, quizAttemptRepo: quizAttemptRepo}
}

// GetUserProfile retrieves the user's profile.
func (s *userService) GetUserProfile(ctx context.Context, userID int64) (*models.User, error) {
	return s.userRepo.GetByID(ctx, userID)
}

// GetOrCreateUser retrieves an existing user or creates a new one
func (s *userService) GetOrCreateUser(ctx context.Context, telegramID int64, firstName, lastName, username, photoURL string) (*models.User, error) {
	// Try to get existing user first
	user, err := s.userRepo.GetByID(ctx, telegramID)
	if err == nil {
		return user, nil
	}

	// If user not found, create new one
	newUser := &models.User{
		TelegramID:   telegramID,
		FirstName:    &firstName,
		LastName:     &lastName,
		Username:     &username,
		StarsBalance: 0,
	}

	// Add photo URL if provided
	if photoURL != "" {
		newUser.PhotoURL = &photoURL
	}

	if err := s.userRepo.CreateUser(ctx, newUser); err != nil {
		return nil, err
	}

	return newUser, nil
}

// GetUserPurchases retrieves the user's purchase history.
func (s *userService) GetUserPurchases(ctx context.Context, userID int64) ([]models.Purchase, error) {
	return s.purchaseRepo.GetByUserID(ctx, userID)
}

// GetUserTransactions retrieves a unified list of all user transactions (earned and spent).
func (s *userService) GetUserTransactions(ctx context.Context, userID int64) ([]models.Transaction, error) {
	var transactions []models.Transaction

	// Get purchases (spent)
	purchases, err := s.purchaseRepo.GetByUserID(ctx, userID)
	if err != nil {
		return nil, err
	}
	for _, p := range purchases {
		transactions = append(transactions, models.Transaction{
			Type:        models.TransactionSpent,
			Amount:      p.StarsSpent,
			Description: "Покупка приза",
			CreatedAt:   p.PurchasedAt,
		})
	}

	// Get quiz attempts (earned)
	attempts, err := s.quizAttemptRepo.GetByUserID(ctx, userID)
	if err != nil {
		return nil, err
	}
	for _, a := range attempts {
		if a.StarsEarned > 0 {
			transactions = append(transactions, models.Transaction{
				Type:        models.TransactionEarned,
				Amount:      a.StarsEarned,
				Description: "Награда за викторину",
				CreatedAt:   a.CompletedAt,
			})
		}
	}

	// Sort transactions by date descending
	sort.Slice(transactions, func(i, j int) bool {
		return transactions[i].CreatedAt.After(transactions[j].CreatedAt)
	})

	return transactions, nil
}
