// ============================================================
// EmailCodeService — 邮件验证码 Redis 缓存层
//
// 职责: 作为 email_verifications 表的快速缓存前置层。
//   - 发送验证码时: setCode() 写入 Redis，TTL = codeExpireSeconds
//   - 验证时: verifyAndDelete() 先查 Redis（O(1)，亚毫秒级）
//   - Redis miss 时: EmailService 回退到 DB 查询（保障可靠性）
//
// Key 模式: auth:email:{TYPE}:{email}
//   示例: auth:email:REGISTER:user@example.com
//         auth:email:LOGIN:user@example.com
//
// 与 SmsCodeService 完全对称，keyPrefix 改为 'auth:email:'。
// Redis 实例与 SmsCodeService 共享相同的 Redis 服务器但各自独立连接。
//
// 设计原则:
//   - Redis 是缓存层，不是主存储，故障时降级到 DB 验证（不影响可用性）
//   - verifyAndDelete 原子性保证验证码一次性消费
//   - retryStrategy: 指数退避，最大重试间隔 2 秒
// ============================================================

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

/**
 * Email code Redis cache service.
 * 作为 DB 持久化的快速缓存层，用于邮件验证码的快速查找。
 * Key pattern: auth:email:{TYPE}:{EMAIL}
 */
@Injectable()
export class EmailCodeService implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger('EmailCodeService');
  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:email:',
      retryStrategy: (times) => Math.min(times * 50, 2000),
    });

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

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

  /**
   * 缓存验证码到 Redis
   */
  async setCode(
    email: string,
    code: string,
    type: EmailVerificationType,
    ttlSeconds = 300,
  ): Promise<void> {
    const key = `${type}:${email}`;
    await this.redis.set(key, code, 'EX', ttlSeconds);
  }

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

  async deleteCode(email: string, type: EmailVerificationType): Promise<void> {
    const key = `${type}:${email}`;
    await this.redis.del(key);
  }
}
