package usecase

import (
	"context"
	"errors"
	"fmt"

	"lune/talentscale/infra/cache"
	"lune/talentscale/internal/domain"

	"github.com/google/uuid"
	"golang.org/x/crypto/bcrypt"
)

type userUsecase struct {
	userRepo domain.UserRepository
}

func NewUserUsecase(userRepo domain.UserRepository) domain.UserUsecase {
	return &userUsecase{
		userRepo: userRepo,
	}
}

func (u *userUsecase) Create(ctx context.Context, user *domain.User) error {
	if user.Email == "" || user.Name == "" || user.Password == "" {
		return errors.New("name, email, and password are required")
	}

	hashed, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	user.Password = string(hashed)

	return u.userRepo.Create(ctx, user)
}

func (u *userUsecase) GetAll(ctx context.Context, companyID uuid.UUID, search string, roleID uuid.UUID, limit, offset int) ([]*domain.User, int, error) {
	return u.userRepo.GetAll(ctx, companyID, search, roleID, limit, offset)
}

func (u *userUsecase) GetByID(ctx context.Context, id uuid.UUID, companyID uuid.UUID) (*domain.User, error) {
	return u.userRepo.GetByID(ctx, id, companyID)
}

func (u *userUsecase) GetByEmail(ctx context.Context, email string) (*domain.User, error) {
	return u.userRepo.GetByEmail(ctx, email)
}

func (u *userUsecase) Update(ctx context.Context, user *domain.User) error {
	if user.CompanyID == nil {
		return errors.New("company_id is required")
	}

	existing, err := u.userRepo.GetByID(ctx, user.ID, *user.CompanyID)
	if err != nil {
		return err
	}
	if existing == nil {
		return errors.New("user not found")
	}

	// Don't update password here, handle it separately if needed
	user.Password = existing.Password

	err = u.userRepo.Update(ctx, user)
	if err == nil {
		// Invalidate permissions cache on user update (role might have changed)
		cacheKey := fmt.Sprintf("user:permissions:%s", user.ID.String())
		_ = cache.Del(cacheKey)
	}
	return err
}

func (u *userUsecase) Delete(ctx context.Context, id uuid.UUID, companyID uuid.UUID) error {
	return u.userRepo.Delete(ctx, id, companyID)
}
