// ============================================================
// EmailVerification Entity — 邮件验证码持久化记录
//
// 表名: email_verifications
// 职责: 持久化邮件验证码，支持多种业务场景（注册/登录/重置密码/换绑邮箱）。
// 与 SmsVerification 结构完全对称，便于统一管理和扩展。
//
// 验证流程 (Redis 快速路径 + DB 兜底):
//   1. 发送时 → create() + Redis.setCode() 同步写入
//   2. 验证时 → 先查 Redis；miss 则查 DB (findLatestValid)
//   3. 验证成功 → markVerified() + Redis.del()
//   4. 失败计数 → incrementAttempts()，超过 maxAttempts 后拒绝
//
// 关键字段:
//   - code: 明文存储的 6 位数字（发送前已由 SmsCode.generate() 生成）
//   - expiresAt: 过期时间（默认 300 秒）
//   - verifiedAt: 验证成功时间（null = 未验证，非 null = 已使用）
//   - attempts: 错误尝试次数（防爆破）
//
// 清理策略: 过期且已验证的记录由定时任务 (deleteExpired) 清理，
// 默认保留 24 小时宽限期，防止迁移/回放场景丢失记录。
// ============================================================

import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  Index,
} from 'typeorm';

export enum EmailVerificationType {
  REGISTER = 'REGISTER',
  LOGIN = 'LOGIN',
  RESET_PASSWORD = 'RESET_PASSWORD',
  CHANGE_EMAIL = 'CHANGE_EMAIL',
}

@Entity('email_verifications')
@Index('idx_email_verif_email_type', ['email', 'type'])
@Index('idx_email_verif_expires', ['expiresAt'])
export class EmailVerification {
  @PrimaryGeneratedColumn('increment', { type: 'bigint' })
  id: string;

  @Column({ type: 'varchar', length: 100 })
  email: string;

  @Column({ type: 'varchar', length: 255 })
  code: string;

  @Column({ type: 'varchar', length: 20 })
  type: EmailVerificationType;

  @Column({ name: 'expires_at', type: 'timestamptz' })
  expiresAt: Date;

  @Column({ name: 'verified_at', type: 'timestamptz', nullable: true })
  verifiedAt: Date | null;

  @Column({ type: 'int', default: 0 })
  attempts: number;

  @CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
  createdAt: Date;

  /* ── Domain Methods ── */

  get isExpired(): boolean {
    return new Date() > this.expiresAt;
  }

  get isVerified(): boolean {
    return this.verifiedAt !== null;
  }

  get isValid(): boolean {
    return !this.isExpired && !this.isVerified;
  }

  canAttempt(maxAttempts: number): boolean {
    return this.attempts < maxAttempts;
  }

  incrementAttempts(): void {
    this.attempts += 1;
  }

  markVerified(): void {
    this.verifiedAt = new Date();
  }
}
