import { AccountSequence, Password, Phone } from '../value-objects';

export enum UserStatus {
  ACTIVE = 'ACTIVE',
  DISABLED = 'DISABLED',
  DELETED = 'DELETED',
}

export enum KycStatus {
  PENDING = 'PENDING',
  SUBMITTED = 'SUBMITTED',
  VERIFIED = 'VERIFIED',
  REJECTED = 'REJECTED',
}

export interface UserProps {
  id?: bigint;
  phone: Phone;
  passwordHash: string;
  tradePasswordHash?: string; // 支付密码（独立于登录密码）
  accountSequence: AccountSequence;
  status: UserStatus;
  kycStatus: KycStatus;
  realName?: string;
  idCardNo?: string;
  idCardFront?: string;
  idCardBack?: string;
  kycSubmittedAt?: Date;
  kycVerifiedAt?: Date;
  kycRejectReason?: string;
  loginFailCount: number;
  lockedUntil?: Date;
  lastLoginAt?: Date;
  lastLoginIp?: string;
  createdAt?: Date;
  updatedAt?: Date;
}

/**
 * 用户聚合根
 */
export class UserAggregate {
  private _id?: bigint;
  private _phone: Phone;
  private _passwordHash: string;
  private _tradePasswordHash?: string; // 支付密码哈希
  private _accountSequence: AccountSequence;
  private _status: UserStatus;
  private _kycStatus: KycStatus;
  private _realName?: string;
  private _idCardNo?: string;
  private _idCardFront?: string;
  private _idCardBack?: string;
  private _kycSubmittedAt?: Date;
  private _kycVerifiedAt?: Date;
  private _kycRejectReason?: string;
  private _loginFailCount: number;
  private _lockedUntil?: Date;
  private _lastLoginAt?: Date;
  private _lastLoginIp?: string;
  private _createdAt?: Date;
  private _updatedAt?: Date;

  private constructor(props: UserProps) {
    this._id = props.id;
    this._phone = props.phone;
    this._passwordHash = props.passwordHash;
    this._tradePasswordHash = props.tradePasswordHash;
    this._accountSequence = props.accountSequence;
    this._status = props.status;
    this._kycStatus = props.kycStatus;
    this._realName = props.realName;
    this._idCardNo = props.idCardNo;
    this._idCardFront = props.idCardFront;
    this._idCardBack = props.idCardBack;
    this._kycSubmittedAt = props.kycSubmittedAt;
    this._kycVerifiedAt = props.kycVerifiedAt;
    this._kycRejectReason = props.kycRejectReason;
    this._loginFailCount = props.loginFailCount;
    this._lockedUntil = props.lockedUntil;
    this._lastLoginAt = props.lastLoginAt;
    this._lastLoginIp = props.lastLoginIp;
    this._createdAt = props.createdAt;
    this._updatedAt = props.updatedAt;
  }

  /**
   * 创建新用户（注册）
   */
  static async create(
    phone: Phone,
    plainPassword: string,
    accountSequence: AccountSequence,
  ): Promise<UserAggregate> {
    const password = await Password.create(plainPassword);
    return new UserAggregate({
      phone,
      passwordHash: password.hash,
      accountSequence,
      status: UserStatus.ACTIVE,
      kycStatus: KycStatus.PENDING,
      loginFailCount: 0,
    });
  }

  /**
   * 从数据库重建
   */
  static reconstitute(props: UserProps): UserAggregate {
    return new UserAggregate(props);
  }

  // Getters
  get id(): bigint | undefined {
    return this._id;
  }

  get phone(): Phone {
    return this._phone;
  }

  get passwordHash(): string {
    return this._passwordHash;
  }

  get tradePasswordHash(): string | undefined {
    return this._tradePasswordHash;
  }

  /**
   * 是否已设置支付密码
   */
  get hasTradePassword(): boolean {
    return this._tradePasswordHash !== undefined && this._tradePasswordHash !== null;
  }

  get accountSequence(): AccountSequence {
    return this._accountSequence;
  }

  get status(): UserStatus {
    return this._status;
  }

  get kycStatus(): KycStatus {
    return this._kycStatus;
  }

  get realName(): string | undefined {
    return this._realName;
  }

  get idCardNo(): string | undefined {
    return this._idCardNo;
  }

  get idCardFront(): string | undefined {
    return this._idCardFront;
  }

  get idCardBack(): string | undefined {
    return this._idCardBack;
  }

  get kycSubmittedAt(): Date | undefined {
    return this._kycSubmittedAt;
  }

  get kycVerifiedAt(): Date | undefined {
    return this._kycVerifiedAt;
  }

  get kycRejectReason(): string | undefined {
    return this._kycRejectReason;
  }

  get loginFailCount(): number {
    return this._loginFailCount;
  }

  get lockedUntil(): Date | undefined {
    return this._lockedUntil;
  }

  get lastLoginAt(): Date | undefined {
    return this._lastLoginAt;
  }

  get lastLoginIp(): string | undefined {
    return this._lastLoginIp;
  }

  get createdAt(): Date | undefined {
    return this._createdAt;
  }

  get updatedAt(): Date | undefined {
    return this._updatedAt;
  }

  /**
   * 判断用户来源
   */
  get source(): 'V1' | 'V2' {
    return this._accountSequence.source;
  }

  /**
   * 是否为 V1 迁移用户
   */
  get isLegacyUser(): boolean {
    return this._accountSequence.isV1;
  }

  /**
   * 是否已锁定
   */
  get isLocked(): boolean {
    return this._lockedUntil !== undefined && this._lockedUntil > new Date();
  }

  /**
   * 是否可登录
   */
  get canLogin(): boolean {
    return this._status === UserStatus.ACTIVE && !this.isLocked;
  }

  /**
   * 是否已完成 KYC
   */
  get isKycVerified(): boolean {
    return this._kycStatus === KycStatus.VERIFIED;
  }

  /**
   * 验证密码
   */
  async verifyPassword(plainPassword: string): Promise<boolean> {
    const password = Password.fromHash(this._passwordHash);
    return password.verify(plainPassword);
  }

  /**
   * 修改密码
   */
  async changePassword(newPlainPassword: string): Promise<void> {
    const password = await Password.create(newPlainPassword);
    this._passwordHash = password.hash;
    this._updatedAt = new Date();
  }

  /**
   * 设置支付密码（6位数字，使用独立的哈希逻辑，不走登录密码的格式验证）
   */
  async setTradePassword(newPlainPassword: string): Promise<void> {
    const password = await Password.createWithoutValidation(newPlainPassword);
    this._tradePasswordHash = password.hash;
    this._updatedAt = new Date();
  }

  /**
   * 验证支付密码
   */
  async verifyTradePassword(plainPassword: string): Promise<boolean> {
    if (!this._tradePasswordHash) {
      return false;
    }
    const password = Password.fromHash(this._tradePasswordHash);
    return password.verify(plainPassword);
  }

  /**
   * 清除支付密码
   */
  clearTradePassword(): void {
    this._tradePasswordHash = undefined;
    this._updatedAt = new Date();
  }

  /**
   * 记录登录成功
   */
  recordLoginSuccess(ip?: string): void {
    this._loginFailCount = 0;
    this._lockedUntil = undefined;
    this._lastLoginAt = new Date();
    this._lastLoginIp = ip;
    this._updatedAt = new Date();
  }

  /**
   * 计算指数退避锁定时间（分钟）
   * 第6次失败: 1分钟
   * 第7次失败: 2分钟
   * 第8次失败: 4分钟
   * 第9次失败: 8分钟
   * 第10次失败: 16分钟
   * ...以此类推，最长24小时
   */
  private calculateLockMinutes(failCount: number, maxAttempts: number): number {
    const excessAttempts = failCount - maxAttempts;
    // 2^(excessAttempts) 分钟，最长 1440 分钟（24小时）
    const lockMinutes = Math.pow(2, excessAttempts);
    return Math.min(lockMinutes, 1440);
  }

  /**
   * 记录登录失败
   * @param maxAttempts 最大尝试次数，默认6次
   * @returns 返回剩余尝试次数和锁定信息
   */
  recordLoginFailure(maxAttempts: number = 6): { remainingAttempts: number; lockedUntil?: Date; lockMinutes?: number } {
    this._loginFailCount += 1;
    this._updatedAt = new Date();

    if (this._loginFailCount >= maxAttempts) {
      const lockMinutes = this.calculateLockMinutes(this._loginFailCount, maxAttempts);
      this._lockedUntil = new Date(Date.now() + lockMinutes * 60 * 1000);
      return {
        remainingAttempts: 0,
        lockedUntil: this._lockedUntil,
        lockMinutes,
      };
    }

    return {
      remainingAttempts: maxAttempts - this._loginFailCount,
    };
  }

  /**
   * 获取剩余尝试次数
   */
  getRemainingAttempts(maxAttempts: number = 6): number {
    return Math.max(0, maxAttempts - this._loginFailCount);
  }

  /**
   * 获取锁定剩余时间（秒）
   */
  getLockRemainingSeconds(): number {
    if (!this._lockedUntil) return 0;
    const remaining = this._lockedUntil.getTime() - Date.now();
    return Math.max(0, Math.ceil(remaining / 1000));
  }

  /**
   * 解锁账户
   */
  unlock(): void {
    this._loginFailCount = 0;
    this._lockedUntil = undefined;
    this._updatedAt = new Date();
  }

  /**
   * 提交 KYC 资料
   */
  submitKyc(
    realName: string,
    idCardNo: string,
    idCardFront: string,
    idCardBack: string,
  ): void {
    if (this._kycStatus === KycStatus.VERIFIED) {
      throw new Error('已完成实名认证，无法重新提交');
    }

    this._realName = realName;
    this._idCardNo = idCardNo;
    this._idCardFront = idCardFront;
    this._idCardBack = idCardBack;
    this._kycStatus = KycStatus.SUBMITTED;
    this._kycSubmittedAt = new Date();
    this._kycRejectReason = undefined;
    this._updatedAt = new Date();
  }

  /**
   * KYC 审核通过
   */
  approveKyc(): void {
    if (this._kycStatus !== KycStatus.SUBMITTED) {
      throw new Error('当前状态无法审核');
    }

    this._kycStatus = KycStatus.VERIFIED;
    this._kycVerifiedAt = new Date();
    this._updatedAt = new Date();
  }

  /**
   * KYC 审核拒绝
   */
  rejectKyc(reason: string): void {
    if (this._kycStatus !== KycStatus.SUBMITTED) {
      throw new Error('当前状态无法审核');
    }

    this._kycStatus = KycStatus.REJECTED;
    this._kycRejectReason = reason;
    this._updatedAt = new Date();
  }

  /**
   * 禁用用户
   */
  disable(): void {
    this._status = UserStatus.DISABLED;
    this._updatedAt = new Date();
  }

  /**
   * 启用用户
   */
  enable(): void {
    this._status = UserStatus.ACTIVE;
    this._updatedAt = new Date();
  }

  /**
   * 删除用户（软删除）
   */
  delete(): void {
    this._status = UserStatus.DELETED;
    this._updatedAt = new Date();
  }

  /**
   * 更换手机号
   */
  changePhone(newPhone: Phone): void {
    this._phone = newPhone;
    this._updatedAt = new Date();
  }

  toSnapshot(): UserProps {
    return {
      id: this._id,
      phone: this._phone,
      passwordHash: this._passwordHash,
      tradePasswordHash: this._tradePasswordHash,
      accountSequence: this._accountSequence,
      status: this._status,
      kycStatus: this._kycStatus,
      realName: this._realName,
      idCardNo: this._idCardNo,
      idCardFront: this._idCardFront,
      idCardBack: this._idCardBack,
      kycSubmittedAt: this._kycSubmittedAt,
      kycVerifiedAt: this._kycVerifiedAt,
      kycRejectReason: this._kycRejectReason,
      loginFailCount: this._loginFailCount,
      lockedUntil: this._lockedUntil,
      lastLoginAt: this._lastLoginAt,
      lastLoginIp: this._lastLoginIp,
      createdAt: this._createdAt,
      updatedAt: this._updatedAt,
    };
  }
}
