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

export enum UserRole {
  USER = 'user',
  ISSUER = 'issuer',
  MARKET_MAKER = 'market_maker',
  ADMIN = 'admin',
}

export enum UserStatus {
  ACTIVE = 'active',
  FROZEN = 'frozen',
  DELETED = 'deleted',
}

@Entity('users')
export class User {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Index('idx_users_phone')
  @Column({ type: 'varchar', length: 20, unique: true, nullable: true })
  phone: string | null;

  @Index('idx_users_email')
  @Column({ type: 'varchar', length: 100, unique: true, nullable: true })
  email: string | null;

  @Column({ name: 'password_hash', type: 'varchar', length: 255 })
  passwordHash: string;

  @Column({ type: 'varchar', length: 50, nullable: true })
  nickname: string | null;

  @Column({ name: 'avatar_url', type: 'varchar', length: 500, nullable: true })
  avatarUrl: string | null;

  @Column({ name: 'kyc_level', type: 'smallint', default: 0 })
  kycLevel: number;

  @Column({
    name: 'wallet_mode',
    type: 'varchar',
    length: 10,
    default: 'standard',
  })
  walletMode: 'standard' | 'external' | 'pro';

  @Index('idx_users_role')
  @Column({
    type: 'varchar',
    length: 20,
    default: UserRole.USER,
  })
  role: UserRole;

  @Index('idx_users_status')
  @Column({
    type: 'varchar',
    length: 20,
    default: UserStatus.ACTIVE,
  })
  status: UserStatus;

  @Column({ name: 'residence_state', type: 'varchar', length: 5, nullable: true })
  residenceState: string | null;

  @Column({ type: 'varchar', length: 5, nullable: true })
  nationality: string | null;

  @Column({ name: 'login_fail_count', type: 'int', default: 0 })
  loginFailCount: number;

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

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

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

  @UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
  updatedAt: Date;

  @VersionColumn({ default: 1 })
  version: number;

  /* ── Domain Methods: Account Lockout ── */

  /** 账号是否处于锁定状态 */
  get isLocked(): boolean {
    return this.lockedUntil !== null && new Date() < this.lockedUntil;
  }

  /** 是否可以登录 (状态正常且未锁定) */
  get canLogin(): boolean {
    return this.status === UserStatus.ACTIVE && !this.isLocked;
  }

  /** 剩余锁定秒数 (0 = 未锁定) */
  get lockRemainingSeconds(): number {
    if (!this.lockedUntil) return 0;
    const diff = this.lockedUntil.getTime() - Date.now();
    return diff > 0 ? Math.ceil(diff / 1000) : 0;
  }

  /**
   * 记录登录成功 — 清除失败计数
   */
  recordLoginSuccess(ip?: string): void {
    this.loginFailCount = 0;
    this.lockedUntil = null;
    this.lastLoginAt = new Date();
  }

  /**
   * 记录登录失败 — 指数退避锁定
   * @param maxAttempts 触发锁定的失败次数阈值 (默认 6)
   * @returns 剩余尝试次数 & 锁定信息
   */
  recordLoginFailure(maxAttempts = 6): {
    remainingAttempts: number;
    lockMinutes?: number;
  } {
    this.loginFailCount += 1;

    if (this.loginFailCount < maxAttempts) {
      return { remainingAttempts: maxAttempts - this.loginFailCount };
    }

    // 指数退避: 2^(failCount - maxAttempts) 分钟，最大 1440 分钟 (24h)
    const lockMinutes = Math.min(
      Math.pow(2, this.loginFailCount - maxAttempts),
      1440,
    );
    this.lockedUntil = new Date(Date.now() + lockMinutes * 60 * 1000);

    return { remainingAttempts: 0, lockMinutes };
  }
}
