import { Injectable, Inject, NotFoundException } from '@nestjs/common';
import { UserEntity, UserType } from '../../domain/entities/user.entity';
import {
  IUserRepository,
  USER_REPOSITORY,
  UserQueryOptions,
  PaginatedUsers,
} from '../../domain/repositories/user.repository.interface';

@Injectable()
export class UserService {
  constructor(
    @Inject(USER_REPOSITORY)
    private readonly userRepo: IUserRepository,
  ) {}

  async createAnonymousUser(fingerprint: string): Promise<UserEntity> {
    const existingUser = await this.userRepo.findByFingerprint(fingerprint);

    if (existingUser) {
      existingUser.updateLastActive();
      return this.userRepo.save(existingUser);
    }

    const user = UserEntity.createAnonymous(fingerprint);
    return this.userRepo.save(user);
  }

  async findById(id: string): Promise<UserEntity> {
    const user = await this.userRepo.findById(id);

    if (!user) {
      throw new NotFoundException('User not found');
    }

    return user;
  }

  async findByFingerprint(fingerprint: string): Promise<UserEntity | null> {
    return this.userRepo.findByFingerprint(fingerprint);
  }

  async findByPhone(phone: string): Promise<UserEntity | null> {
    return this.userRepo.findByPhone(phone);
  }

  async upgradeToRegistered(userId: string, phone: string): Promise<UserEntity> {
    const user = await this.findById(userId);

    const existingPhoneUser = await this.findByPhone(phone);
    if (existingPhoneUser && existingPhoneUser.id !== userId) {
      throw new Error('Phone number already registered');
    }

    user.upgradeToRegistered(phone);
    return this.userRepo.save(user);
  }

  async updateLastActive(userId: string): Promise<void> {
    await this.userRepo.updateLastActive(userId);
  }

  async updateProfile(
    userId: string,
    data: { nickname?: string; avatar?: string },
  ): Promise<UserEntity> {
    const user = await this.findById(userId);
    user.updateProfile(data);
    return this.userRepo.save(user);
  }

  // Admin methods
  async findAll(options: UserQueryOptions): Promise<PaginatedUsers> {
    return this.userRepo.findAll(options);
  }

  async countByType(): Promise<Record<UserType, number>> {
    return this.userRepo.countByType();
  }

  async searchUsers(keyword: string, limit?: number): Promise<UserEntity[]> {
    return this.userRepo.search(keyword, limit);
  }
}
