package core

import (
	"context"
	"errors"
	"fmt"
	"log"
	"regexp"

	"gitea.mrixs.me/minecraft-platform/backend/internal/database"
	"gitea.mrixs.me/minecraft-platform/backend/internal/models"
	"github.com/google/uuid"
	"golang.org/x/crypto/bcrypt"
)

var (
	ErrInvalidUsername  = errors.New("invalid username format or length")
	ErrInvalidEmail     = errors.New("invalid email format")
	ErrPasswordTooShort = errors.New("password is too short (minimum 8 characters)")
)

var usernameRegex = regexp.MustCompile(`^[a-zA-Z0-9_]{3,16}$`)

var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)

type UserService struct {
	Repo *database.UserRepository
}

// RegisterNewUser выполняет полный алгоритм регистрации
func (s *UserService) RegisterNewUser(ctx context.Context, req models.RegisterRequest) error {
	if !usernameRegex.MatchString(req.Username) {
		return ErrInvalidUsername
	}
	if !emailRegex.MatchString(req.Email) {
		return ErrInvalidEmail
	}
	if len(req.Password) < 8 {
		return ErrPasswordTooShort
	}

	passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 12)
	if err != nil {
		return err
	}

	userUUID, err := uuid.NewRandom()
	if err != nil {
		return err
	}

	user := &models.User{
		UUID:         userUUID,
		Username:     req.Username,
		Email:        req.Email,
		PasswordHash: string(passwordHash),
		Role:         "user",
	}

	return s.Repo.CreateUserTx(ctx, user)
}

// GetUserByID возвращает пользователя по его ID
func (s *UserService) GetUserByID(ctx context.Context, userID int) (*models.User, error) {
	return s.Repo.GetUserByID(ctx, userID)
}

// ValidateJoinRequest проверяет запрос на присоединение к серверу.
func (s *AuthService) ValidateJoinRequest(ctx context.Context, req models.JoinRequest) error {
	var uuidStr string
	if len(req.SelectedProfile) == 32 {
		uuidStr = fmt.Sprintf("%s-%s-%s-%s-%s",
			req.SelectedProfile[0:8],
			req.SelectedProfile[8:12],
			req.SelectedProfile[12:16],
			req.SelectedProfile[16:20],
			req.SelectedProfile[20:32],
		)
	} else {
		return errors.New("invalid profile UUID format")
	}

	userUUID, err := uuid.Parse(uuidStr)
	if err != nil {
		return fmt.Errorf("failed to parse profile UUID: %w", err)
	}

	err = s.UserRepo.ValidateAccessToken(ctx, req.AccessToken, userUUID)
	if err != nil {
		if errors.Is(err, database.ErrTokenNotFound) {
			return ErrInvalidCredentials
		}
		return err
	}

	log.Printf("User %s successfully joined server with serverId %s", userUUID, req.ServerID)

	return nil
}
