import { Injectable, Inject, BadRequestException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
  Phone,
  SmsCode,
  SMS_VERIFICATION_REPOSITORY,
  SmsVerificationRepository,
  SmsVerificationType,
  USER_REPOSITORY,
  UserRepository,
  SYNCED_LEGACY_USER_REPOSITORY,
  SyncedLegacyUserRepository,
} from '@/domain';

export interface SendSmsDto {
  phone: string;
  type: SmsVerificationType;
}

export interface VerifySmsDto {
  phone: string;
  code: string;
  type: SmsVerificationType;
}

@Injectable()
export class SmsService {
  private readonly codeExpireSeconds: number;
  private readonly dailyLimit: number;
  private readonly maxAttempts = 5;

  constructor(
    @Inject(SMS_VERIFICATION_REPOSITORY)
    private readonly smsVerificationRepository: SmsVerificationRepository,
    @Inject(USER_REPOSITORY)
    private readonly userRepository: UserRepository,
    @Inject(SYNCED_LEGACY_USER_REPOSITORY)
    private readonly syncedLegacyUserRepository: SyncedLegacyUserRepository,
    private readonly configService: ConfigService,
  ) {
    this.codeExpireSeconds = this.configService.get<number>('SMS_CODE_EXPIRE_SECONDS', 300);
    this.dailyLimit = this.configService.get<number>('SMS_DAILY_LIMIT', 10);
  }

  /**
   * 发送短信验证码
   */
  async sendCode(dto: SendSmsDto): Promise<{ expiresIn: number }> {
    const phone = Phone.create(dto.phone);

    // 检查每日发送限制
    const dailyCount = await this.smsVerificationRepository.getDailySendCount(phone);
    if (dailyCount >= this.dailyLimit) {
      throw new BadRequestException('今日发送次数已达上限，请明天再试');
    }

    // 根据类型进行额外验证
    await this.validateSendRequest(phone, dto.type);

    // 生成验证码
    const code = SmsCode.generate();
    const expiresAt = new Date(Date.now() + this.codeExpireSeconds * 1000);

    // 保存验证码
    await this.smsVerificationRepository.create({
      phone,
      code: code.value,
      type: dto.type,
      expiresAt,
    });

    // TODO: 调用阿里云短信 API 发送
    await this.sendSmsToProvider(phone.value, code.value, dto.type);

    return { expiresIn: this.codeExpireSeconds };
  }

  /**
   * 验证短信验证码
   */
  async verifyCode(dto: VerifySmsDto): Promise<boolean> {
    const phone = Phone.create(dto.phone);

    const verification = await this.smsVerificationRepository.findLatestValid(phone, dto.type);
    if (!verification) {
      throw new BadRequestException('验证码已过期或不存在');
    }

    if (verification.attempts >= this.maxAttempts) {
      throw new BadRequestException('验证码尝试次数过多，请重新获取');
    }

    if (verification.code !== dto.code) {
      await this.smsVerificationRepository.incrementAttempts(verification.id);
      throw new BadRequestException('验证码错误');
    }

    await this.smsVerificationRepository.markAsVerified(verification.id);
    return true;
  }

  /**
   * 根据发送类型进行验证
   */
  private async validateSendRequest(phone: Phone, type: SmsVerificationType): Promise<void> {
    const user = await this.userRepository.findByPhone(phone);
    const legacyUser = await this.syncedLegacyUserRepository.findByPhone(phone);

    switch (type) {
      case SmsVerificationType.REGISTER:
        // 注册：手机号不能已存在
        if (user) {
          throw new BadRequestException('手机号已注册');
        }
        if (legacyUser && !legacyUser.migratedToV2) {
          throw new BadRequestException('此手机号已在1.0系统注册，请直接登录');
        }
        break;

      case SmsVerificationType.LOGIN:
      case SmsVerificationType.RESET_PASSWORD:
        // 登录/重置密码：手机号必须已存在
        if (!user && !(legacyUser && !legacyUser.migratedToV2)) {
          throw new BadRequestException('手机号未注册');
        }
        break;

      case SmsVerificationType.CHANGE_PHONE:
        // 更换手机号：新手机号不能已存在
        if (user || (legacyUser && !legacyUser.migratedToV2)) {
          throw new BadRequestException('手机号已被使用');
        }
        break;
    }
  }

  /**
   * 调用短信服务商发送（阿里云）
   */
  private async sendSmsToProvider(
    phone: string,
    code: string,
    type: SmsVerificationType,
  ): Promise<void> {
    // TODO: 实现阿里云短信发送
    // const accessKeyId = this.configService.get<string>('SMS_ACCESS_KEY_ID');
    // const accessKeySecret = this.configService.get<string>('SMS_ACCESS_KEY_SECRET');
    // const signName = this.configService.get<string>('SMS_SIGN_NAME');
    // const templateCode = this.configService.get<string>('SMS_TEMPLATE_CODE');

    // 开发环境打印验证码
    if (this.configService.get('NODE_ENV') === 'development') {
      console.log(`[SMS] Phone: ${phone}, Code: ${code}, Type: ${type}`);
    }
  }
}
