import { DataSource } from 'typeorm';
import { UserEntity as User } from './user.entity';
import * as bcrypt from 'bcrypt';
import { Repository } from 'typeorm';
import { Role } from './role.entity';

const SALT_ROUNDS = 10;

export class UserService {
  private userRepository: Repository<User>;
  private roleRepository: Repository<Role>;
  private readonly dataSource: DataSource;

  constructor(dataSource: DataSource) {
    this.dataSource = dataSource;
    this.userRepository = this.dataSource.getRepository(User);
    this.roleRepository = this.dataSource.getRepository(Role);
  }

  async createUser(userData: Partial<User>): Promise<User> {
    try {
      if (userData.password) {
        userData.password = await bcrypt.hash(userData.password, SALT_ROUNDS);
      }
      const user = this.userRepository.create(userData);
      return await this.userRepository.save(user);
    } catch (error) {
      console.error('Error creating user:', error);
      throw new Error(`Failed to create user: ${error instanceof Error ? error.message : String(error)}`)
    }
  }

  async getUserById(id: number): Promise<User | null> {
    try {
      return await this.userRepository.findOne({ 
        where: { id },
        relations: ['roles', 'avatarFile']
      });
    } catch (error) {
      console.error('Error getting user:', error);
      throw new Error('Failed to get user');
    }
  }

  async getUserByUsername(username: string): Promise<User | null> {
    try {
      return await this.userRepository.findOne({
        where: { username },
        relations: ['roles', 'avatarFile']
      });
    } catch (error) {
      console.error('Error getting user:', error);
      throw new Error('Failed to get user');
    }
  }

  async getUserByPhone(phone: string): Promise<User | null> {
    try {
      return await this.userRepository.findOne({
        where: { phone: phone },
        relations: ['roles', 'avatarFile']
      });
    } catch (error) {
      console.error('Error getting user by phone:', error);
      throw new Error('Failed to get user by phone');
    }
  }

  async updateUser(id: number, updateData: Partial<User>): Promise<User | null> {
    try {
      if (updateData.password) {
        updateData.password = await bcrypt.hash(updateData.password, SALT_ROUNDS);
      }
      await this.userRepository.update(id, updateData);
      return this.getUserById(id);
    } catch (error) {
      console.error('Error updating user:', error);
      throw new Error('Failed to update user');
    }
  }

  async deleteUser(id: number): Promise<boolean> {
    try {
      const result = await this.userRepository.delete(id);
      return result.affected !== null && result.affected !== undefined &&  result.affected > 0;
    } catch (error) {
      console.error('Error deleting user:', error);
      throw new Error('Failed to delete user');
    }
  }


  async verifyPassword(user: User, password: string): Promise<boolean> {
    return password === user.password || bcrypt.compare(password, user.password)
  }

  async assignRoles(userId: number, roleIds: number[]): Promise<User | null> {
    try {
      const user = await this.getUserById(userId);
      if (!user) return null;

      const roles = await this.roleRepository.findByIds(roleIds);
      user.roles = roles;
      return await this.userRepository.save(user);
    } catch (error) {
      console.error('Error assigning roles:', error);
      throw new Error('Failed to assign roles');
    }
  }

  async getUsers(): Promise<User[]> {
    try {
      const users = await this.userRepository.find({
        relations: ['roles', 'avatarFile']
      });
      return users;
    } catch (error) {
      console.error('Error getting users:', error);
      throw new Error(`Failed to get users: ${error instanceof Error ? error.message : String(error)}`)
    }
  }


  getUserRepository(): Repository<User> {
    return this.userRepository;
  }

  async getUserByAccount(account: string): Promise<User | null> {
    try {
      return await this.userRepository.findOne({
        where: [{ username: account }, { email: account }],
        relations: ['roles', 'avatarFile']
      });
    } catch (error) {
      console.error('Error getting user by account:', error);
      throw new Error('Failed to get user by account');
    }
  }
}