import { Injectable, Inject } from '@nestjs/common';
import { BindPhoneCommand } from './bind-phone.command';
import {
  UserAccountRepository,
  USER_ACCOUNT_REPOSITORY,
} from '@/domain/repositories/user-account.repository.interface';
import { UserValidatorService } from '@/domain/services';
import { UserId, PhoneNumber } from '@/domain/value-objects';
import { RedisService } from '@/infrastructure/redis/redis.service';
import { EventPublisherService } from '@/infrastructure/kafka/event-publisher.service';
import { ApplicationError } from '@/shared/exceptions/domain.exception';

@Injectable()
export class BindPhoneHandler {
  constructor(
    @Inject(USER_ACCOUNT_REPOSITORY)
    private readonly userRepository: UserAccountRepository,
    private readonly validatorService: UserValidatorService,
    private readonly redisService: RedisService,
    private readonly eventPublisher: EventPublisherService,
  ) {}

  async execute(command: BindPhoneCommand): Promise<void> {
    const account = await this.userRepository.findById(
      UserId.create(command.userId),
    );
    if (!account) throw new ApplicationError('用户不存在');

    const phoneNumber = PhoneNumber.create(command.phoneNumber);
    const cachedCode = await this.redisService.get(
      `sms:bind:${phoneNumber.value}`,
    );
    if (cachedCode !== command.smsCode)
      throw new ApplicationError('验证码错误或已过期');

    const validation =
      await this.validatorService.validatePhoneNumber(phoneNumber);
    if (!validation.isValid)
      throw new ApplicationError(validation.errorMessage!);

    account.bindPhoneNumber(phoneNumber);
    await this.userRepository.save(account);
    await this.redisService.delete(`sms:bind:${phoneNumber.value}`);
    await this.eventPublisher.publishAll(account.domainEvents);
    account.clearDomainEvents();
  }
}
