package auth

import (
	"context"

	"counter/internal/domain/entities"
	"counter/internal/domain/repositories"
	"counter/internal/infrastructure/security"
)

// AuthService handles authentication business logic
type AuthService struct {
	userRepo        repositories.UserRepository
	passwordService security.PasswordService
	jwtService      security.JWTService
}

// NewAuthService creates a new authentication service
func NewAuthService(
	userRepo repositories.UserRepository,
	passwordService security.PasswordService,
	jwtService security.JWTService,
) *AuthService {
	return &AuthService{
		userRepo:        userRepo,
		passwordService: passwordService,
		jwtService:      jwtService,
	}
}

// RegisterRequest represents a user registration request
type RegisterRequest struct {
	Username string `json:"username" binding:"required,min=3,max=50"`
	Email    string `json:"email" binding:"required,email"`
	Password string `json:"password" binding:"required,min=6"`
}

// LoginRequest represents a user login request
type LoginRequest struct {
	Username string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required"`
}

// AuthResponse represents an authentication response
type AuthResponse struct {
	Token string         `json:"token"`
	User  *entities.User `json:"user"`
}

// Register registers a new user
func (s *AuthService) Register(ctx context.Context, req *RegisterRequest) (*AuthResponse, error) {
	// Check if username already exists
	_, err := s.userRepo.FindByUsername(ctx, req.Username)
	if err == nil {
		return nil, entities.ErrUserAlreadyExists
	}
	if err != entities.ErrUserNotFound {
		return nil, err
	}

	// Check if email already exists
	_, err = s.userRepo.FindByEmail(ctx, req.Email)
	if err == nil {
		return nil, entities.ErrUserAlreadyExists
	}
	if err != entities.ErrUserNotFound {
		return nil, err
	}

	// Hash password
	hashedPassword, err := s.passwordService.HashPassword(req.Password)
	if err != nil {
		return nil, err
	}

	// Create user
	user := &entities.User{
		Username: req.Username,
		Email:    req.Email,
		Password: hashedPassword,
	}

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

	// Generate token
	token, err := s.jwtService.GenerateToken(user.ID, user.Username)
	if err != nil {
		return nil, err
	}

	// Clear password from response
	user.ClearPassword()

	return &AuthResponse{
		Token: token,
		User:  user,
	}, nil
}

// Login authenticates a user
func (s *AuthService) Login(ctx context.Context, req *LoginRequest) (*AuthResponse, error) {
	// Find user
	user, err := s.userRepo.FindByUsername(ctx, req.Username)
	if err != nil {
		return nil, entities.ErrInvalidCredentials
	}

	// Check password
	if !s.passwordService.CheckPasswordHash(req.Password, user.Password) {
		return nil, entities.ErrInvalidCredentials
	}

	// Generate token
	token, err := s.jwtService.GenerateToken(user.ID, user.Username)
	if err != nil {
		return nil, err
	}

	// Clear password from response
	user.ClearPassword()

	return &AuthResponse{
		Token: token,
		User:  user,
	}, nil
}

// GetCurrentUser retrieves the current authenticated user
func (s *AuthService) GetCurrentUser(ctx context.Context, userID int) (*entities.User, error) {
	user, err := s.userRepo.FindByID(ctx, userID)
	if err != nil {
		return nil, err
	}

	// Clear password from response
	user.ClearPassword()

	return user, nil
}
