import { Injectable, Logger, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import Redis from 'ioredis';
import { SmsVerificationType } from '../../domain/entities/sms-verification.entity';

/**
 * SMS code Redis cache service.
 * 作为 DB 持久化的快速缓存层，用于验证码的快速查找。
 * Key pattern: auth:sms:{type}:{phone}
 */
@Injectable()
export class SmsCodeService implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger('SmsCodeService');
  private redis: Redis;

  async onModuleInit() {
    const host = process.env.REDIS_HOST || 'localhost';
    const port = parseInt(process.env.REDIS_PORT || '6379', 10);
    const password = process.env.REDIS_PASSWORD || undefined;

    this.redis = new Redis({
      host,
      port,
      password,
      keyPrefix: 'auth:sms:',
      retryStrategy: (times) => Math.min(times * 50, 2000),
    });

    this.redis.on('connect', () => this.logger.log('Redis connected for SMS code service'));
    this.redis.on('error', (err) => this.logger.error(`Redis error: ${err.message}`));
  }

  async onModuleDestroy() {
    if (this.redis) {
      await this.redis.quit();
    }
  }

  /**
   * 缓存验证码到 Redis
   * @param phone E.164 格式手机号
   * @param code 6位验证码
   * @param type 验证码类型
   * @param ttlSeconds 过期秒数 (默认 300)
   */
  async setCode(
    phone: string,
    code: string,
    type: SmsVerificationType,
    ttlSeconds = 300,
  ): Promise<void> {
    const key = `${type}:${phone}`;
    await this.redis.set(key, code, 'EX', ttlSeconds);
  }

  /**
   * 从 Redis 验证验证码
   * @returns true=匹配并删除, false=不匹配或不存在
   */
  async verifyAndDelete(
    phone: string,
    code: string,
    type: SmsVerificationType,
  ): Promise<boolean> {
    const key = `${type}:${phone}`;
    const stored = await this.redis.get(key);
    if (!stored || stored !== code) {
      return false;
    }
    await this.redis.del(key);
    return true;
  }

  /**
   * 删除缓存的验证码
   */
  async deleteCode(phone: string, type: SmsVerificationType): Promise<void> {
    const key = `${type}:${phone}`;
    await this.redis.del(key);
  }

  /* ── Legacy compatibility (used by existing auth.service) ── */

  /** @deprecated Use setCode() with type parameter */
  async generateCode(phone: string): Promise<string> {
    const code = String(Math.floor(100000 + Math.random() * 900000));
    await this.redis.set(phone, code, 'EX', 300);
    this.logger.log(`[DEV] SMS code for ${phone}: ${code}`);
    return code;
  }

  /** @deprecated Use verifyAndDelete() with type parameter */
  async verifyCode(phone: string, code: string): Promise<boolean> {
    const stored = await this.redis.get(phone);
    if (!stored || stored !== code) {
      return false;
    }
    await this.redis.del(phone);
    return true;
  }
}
