import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { Types } from 'mongoose';
import { UsersRepository } from '../users/users.repository';
import { BlocksRepository } from './blocks.repository';

@Injectable()
export class BlocksService {
  constructor(
    private readonly blocksRepository: BlocksRepository,
    private readonly usersRepository: UsersRepository,
  ) {}

  async block(currentUserId: string, targetUserId: string) {
    this.assertValidTarget(currentUserId, targetUserId);
    const target = await this.usersRepository.findById(targetUserId);
    if (!target || target.isDisabled) {
      throw new NotFoundException('Target user not found');
    }

    await this.blocksRepository.create(currentUserId, targetUserId);
    return { blocked: true, targetUserId };
  }

  async unblock(currentUserId: string, targetUserId: string) {
    this.assertValidTarget(currentUserId, targetUserId);
    await this.blocksRepository.remove(currentUserId, targetUserId);
    return { blocked: false, targetUserId };
  }

  async getStatus(currentUserId: string, targetUserId: string) {
    this.assertValidTarget(currentUserId, targetUserId);
    const [iBlocked, blockedMe] = await Promise.all([
      this.blocksRepository.findOne(currentUserId, targetUserId),
      this.blocksRepository.findOne(targetUserId, currentUserId),
    ]);

    return { targetUserId, iBlocked: !!iBlocked, blockedMe: !!blockedMe };
  }

  async getBlockedIds(currentUserId: string): Promise<string[]> {
    return this.blocksRepository.findBlockedIds(currentUserId);
  }

  async getInvisibleUserIds(currentUserId: string): Promise<string[]> {
    return this.blocksRepository.findBlockingOrBlockedIds(currentUserId);
  }

  async assertNoBlockBetween(currentUserId: string, targetUserId: string): Promise<void> {
    this.assertValidTarget(currentUserId, targetUserId);
    const block = await this.blocksRepository.findAnyBetween(currentUserId, targetUserId);
    if (block) {
      throw new NotFoundException('User not found');
    }
  }

  private assertValidTarget(currentUserId: string, targetUserId: string): void {
    if (!Types.ObjectId.isValid(targetUserId)) {
      throw new BadRequestException('Invalid target user id');
    }
    if (currentUserId === targetUserId) {
      throw new BadRequestException('You cannot block yourself');
    }
  }
}
