import { ConflictException, Inject } from '@nestjs/common';
import { CommandHandler, type ICommandHandler } from '@nestjs/cqrs';
import { createId } from '@paralleldrive/cuid2';
import { PrismaService, ValidationException } from '@modules/shared';
import { USER_REPOSITORY, type IUserRepository } from '../../../../auth/domain/repositories/user.repository';
import { UserEntity } from '../../../../auth/domain/entities/user.entity';
import { Email } from '../../../../auth/domain/value-objects/email.vo';
import { HashedPassword } from '../../../../auth/domain/value-objects/hashed-password.vo';
import { Phone } from '../../../../auth/domain/value-objects/phone.vo';
import { ProvisionParkOperatorCommand } from './provision-park-operator.command';

export interface ProvisionParkOperatorResult {
  userId: string;
  phone: string;
  email: string | null;
  fullName: string;
  linkedParkIds: string[];
}

@CommandHandler(ProvisionParkOperatorCommand)
export class ProvisionParkOperatorHandler
  implements ICommandHandler<ProvisionParkOperatorCommand, ProvisionParkOperatorResult>
{
  constructor(
    @Inject(USER_REPOSITORY) private readonly userRepo: IUserRepository,
    private readonly prisma: PrismaService,
  ) {}

  async execute(cmd: ProvisionParkOperatorCommand): Promise<ProvisionParkOperatorResult> {
    const phoneResult = Phone.create(cmd.phone);
    if (phoneResult.isErr) throw new ValidationException(phoneResult.unwrapErr());
    const phone = phoneResult.unwrap();

    let email: Email | undefined;
    if (cmd.email) {
      const emailResult = Email.create(cmd.email);
      if (emailResult.isErr) throw new ValidationException(emailResult.unwrapErr());
      email = emailResult.unwrap();
    }

    const passwordResult = await HashedPassword.fromPlain(cmd.password);
    if (passwordResult.isErr) throw new ValidationException(passwordResult.unwrapErr());
    const passwordHash = passwordResult.unwrap();

    if (await this.userRepo.findByPhone(phone.value)) {
      throw new ConflictException('Số điện thoại đã được đăng ký');
    }
    if (email && (await this.userRepo.findByEmail(email.value))) {
      throw new ConflictException('Email đã được đăng ký');
    }

    if (cmd.parkIds.length > 0) {
      const rows = await this.prisma.industrialPark.findMany({
        where: { id: { in: cmd.parkIds } },
        select: { id: true, ownerId: true, name: true },
      });
      const byId = new Map(rows.map((r) => [r.id, r]));
      const missing = cmd.parkIds.filter((id) => !byId.has(id));
      if (missing.length > 0) {
        throw new ValidationException(`Không tìm thấy KCN: ${missing.join(', ')}`);
      }
      const occupied = rows.filter((r) => r.ownerId && r.ownerId !== null);
      if (occupied.length > 0) {
        throw new ConflictException(
          `Các KCN đã có đơn vị vận hành khác: ${occupied.map((r) => r.name).join(', ')}`,
        );
      }
    }

    const user = UserEntity.createNew(
      createId(),
      phone,
      cmd.fullName,
      passwordHash,
      email,
      'PARK_OPERATOR',
    );
    await this.userRepo.save(user);

    if (cmd.parkIds.length > 0) {
      await this.prisma.industrialPark.updateMany({
        where: { id: { in: cmd.parkIds } },
        data: { ownerId: user.id },
      });
    }

    return {
      userId: user.id,
      phone: user.phone.value,
      email: user.email?.value ?? null,
      fullName: user.fullName,
      linkedParkIds: cmd.parkIds,
    };
  }
}
