import bcrypt from 'bcrypt';
import { EntityManager } from '@mikro-orm/core';
import { User } from '../entities/user/_User';
import { UserRepository } from '../repositories/UserRepository';
import { UserRoleRepository } from '../repositories/UserRoleRepository';
import { UserRoleType } from '@/constants/roles';

export class UserService {
    constructor(
        private readonly em: EntityManager,
        private readonly userRepository: UserRepository,
        private readonly userRoleRepository: UserRoleRepository
    ) {}

    getAllUsers() {
        try {
            return this.userRepository.findAllUsers();
        } catch (error) {
            throw new Error('Error fetching users');
        }
    }

    async getUserById(id: number) {
        try {
            return await this.userRepository.findUserById(id);
        } catch (error) {
            throw new Error('Error fetching user by ID');
        }
    }

    async getUserByUsername(username: string) {
        try {
            return await this.userRepository.findUserByUsername(username);
        } catch (error) {
            throw new Error('Error fetching user by username');
        }
    }

    async createUserWithRole(
        username: string,
        password: string,
        email: string,
        roleName: UserRoleType
    ) {
        try {
            const user = new User();
            user.username = username;
            user.password = password; // Let the entity handle password hashing
            user.email = email;

            const role = await this.userRoleRepository.findRoleByName(roleName);
            if (!role) {
                throw new Error(`Role '${roleName}' does not exist!`);
            }

            user.roles.add(role);
            await this.em.persistAndFlush(user);

            return user;
        } catch (error) {
            console.error('Error creating user:', error);
            throw new Error('Error creating user with role');
        }
    }

    async authenticateUser(username: string, password: string) {
        try {
            const user = await this.userRepository.findUserByUsername(username);
            if (!user) {
                throw new Error('User not found');
            }

            const isPasswordValid = await bcrypt.compare(password, user.password);
            if (!isPasswordValid) {
                throw new Error('Invalid password');
            }

            return user;
        } catch (error) {
            throw new Error('Error during authentication');
        }
    }
}
