import { DomainError } from '@/shared/exceptions/domain.exception';
import {
  createHash,
  createCipheriv,
  createDecipheriv,
  randomBytes,
  scryptSync,
} from 'crypto';
import * as bip39 from '@scure/bip39';
import { wordlist } from '@scure/bip39/wordlists/english';

// ============ UserId ============
export class UserId {
  constructor(public readonly value: bigint) {
    // 允许 0 作为临时值（表示未持久化的新账户）
    if (value === null || value === undefined) {
      throw new DomainError('UserId不能为空');
    }
  }

  static create(value: bigint | string | number): UserId {
    if (typeof value === 'string') {
      return new UserId(BigInt(value));
    }
    if (typeof value === 'number') {
      return new UserId(BigInt(value));
    }
    return new UserId(value);
  }

  equals(other: UserId): boolean {
    return this.value === other.value;
  }

  toString(): string {
    return this.value.toString();
  }
}

// ============ AccountSequence ============
// 导出新格式的账户序列号 (D + YYMMDD + 5位序号)
export { AccountSequence } from './account-sequence.vo';

// ============ PhoneNumber ============
export class PhoneNumber {
  constructor(public readonly value: string) {
    if (!/^1[3-9]\d{9}$/.test(value)) {
      throw new DomainError('手机号格式错误');
    }
  }

  static create(value: string): PhoneNumber {
    return new PhoneNumber(value);
  }

  equals(other: PhoneNumber): boolean {
    return this.value === other.value;
  }

  masked(): string {
    return this.value.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
  }
}

// ============ ReferralCode ============
export class ReferralCode {
  constructor(public readonly value: string) {
    if (!/^[A-Z0-9]{6}$/.test(value)) {
      throw new DomainError('推荐码格式错误');
    }
  }

  static generate(): ReferralCode {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    let code = '';
    for (let i = 0; i < 6; i++) {
      code += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return new ReferralCode(code);
  }

  static create(value: string): ReferralCode {
    return new ReferralCode(value.toUpperCase());
  }

  equals(other: ReferralCode): boolean {
    return this.value === other.value;
  }
}

// ============ Mnemonic ============
export class Mnemonic {
  constructor(public readonly value: string) {
    if (!bip39.validateMnemonic(value, wordlist)) {
      throw new DomainError('助记词格式错误');
    }
  }

  static generate(): Mnemonic {
    const mnemonic = bip39.generateMnemonic(wordlist, 128);
    return new Mnemonic(mnemonic);
  }

  static create(value: string): Mnemonic {
    return new Mnemonic(value);
  }

  toSeed(): Uint8Array {
    return bip39.mnemonicToSeedSync(this.value);
  }

  getWords(): string[] {
    return this.value.split(' ');
  }

  equals(other: Mnemonic): boolean {
    return this.value === other.value;
  }
}

// ============ DeviceInfo ============
// deviceInfo: 完整的设备信息 JSON，100% 保持前端传递的原样
export class DeviceInfo {
  private _lastActiveAt: Date;
  private _deviceInfo: Record<string, unknown>;

  constructor(
    public readonly deviceId: string,
    public readonly deviceName: string,
    public readonly addedAt: Date,
    lastActiveAt: Date,
    deviceInfo?: Record<string, unknown>,
  ) {
    this._lastActiveAt = lastActiveAt;
    this._deviceInfo = deviceInfo || {};
  }

  get lastActiveAt(): Date {
    return this._lastActiveAt;
  }

  // 100% 保持原样的完整设备信息 JSON
  get deviceInfo(): Record<string, unknown> {
    return this._deviceInfo;
  }

  // 便捷访问器
  get platform(): string | undefined {
    return this._deviceInfo.platform as string | undefined;
  }

  get deviceModel(): string | undefined {
    return (this._deviceInfo.model || this._deviceInfo.deviceModel) as
      | string
      | undefined;
  }

  get osVersion(): string | undefined {
    return this._deviceInfo.osVersion as string | undefined;
  }

  get appVersion(): string | undefined {
    return this._deviceInfo.appVersion as string | undefined;
  }

  updateActivity(): void {
    this._lastActiveAt = new Date();
  }

  updateDeviceInfo(info: Record<string, unknown>): void {
    this._deviceInfo = { ...this._deviceInfo, ...info };
  }
}

// ============ ChainType ============
export enum ChainType {
  KAVA = 'KAVA',
  DST = 'DST',
  BSC = 'BSC',
}

export const CHAIN_CONFIG = {
  [ChainType.KAVA]: { prefix: 'kava', derivationPath: "m/44'/459'/0'/0/0" },
  [ChainType.DST]: { prefix: 'dst', derivationPath: "m/44'/118'/0'/0/0" },
  [ChainType.BSC]: { prefix: '0x', derivationPath: "m/44'/60'/0'/0/0" },
};

// ============ KYCInfo ============
export class KYCInfo {
  constructor(
    public readonly realName: string,
    public readonly idCardNumber: string,
    public readonly idCardFrontUrl: string,
    public readonly idCardBackUrl: string,
  ) {
    if (!realName || realName.length < 2) {
      throw new DomainError('真实姓名不合法');
    }
    if (
      !/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9Xx]$/.test(
        idCardNumber,
      )
    ) {
      throw new DomainError('身份证号格式错误');
    }
  }

  static create(params: {
    realName: string;
    idCardNumber: string;
    idCardFrontUrl: string;
    idCardBackUrl: string;
  }): KYCInfo {
    return new KYCInfo(
      params.realName,
      params.idCardNumber,
      params.idCardFrontUrl,
      params.idCardBackUrl,
    );
  }

  maskedIdCardNumber(): string {
    return this.idCardNumber.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2');
  }
}

// ============ Enums ============
export enum KYCStatus {
  NOT_VERIFIED = 'NOT_VERIFIED',
  PENDING = 'PENDING',
  VERIFIED = 'VERIFIED',
  REJECTED = 'REJECTED',
}

export enum AccountStatus {
  ACTIVE = 'ACTIVE',
  FROZEN = 'FROZEN',
  DEACTIVATED = 'DEACTIVATED',
}

export enum AddressStatus {
  ACTIVE = 'ACTIVE',
  DISABLED = 'DISABLED',
}

// ============ AddressId ============
export class AddressId {
  constructor(public readonly value: string) {}

  static generate(): AddressId {
    return new AddressId(crypto.randomUUID());
  }

  static create(value: string): AddressId {
    return new AddressId(value);
  }
}

// ============ MnemonicEncryption ============
export class MnemonicEncryption {
  static encrypt(mnemonic: string, key: string): string {
    const derivedKey = this.deriveKey(key);
    const iv = randomBytes(16);
    const cipher = createCipheriv('aes-256-gcm', derivedKey, iv);

    let encrypted = cipher.update(mnemonic, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    const authTag = cipher.getAuthTag();

    return JSON.stringify({
      encrypted,
      authTag: authTag.toString('hex'),
      iv: iv.toString('hex'),
    });
  }

  static decrypt(encryptedData: string, key: string): string {
    const { encrypted, authTag, iv } = JSON.parse(encryptedData);
    const derivedKey = this.deriveKey(key);
    const decipher = createDecipheriv(
      'aes-256-gcm',
      derivedKey,
      Buffer.from(iv, 'hex'),
    );
    decipher.setAuthTag(Buffer.from(authTag, 'hex'));

    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
  }

  private static deriveKey(password: string): Buffer {
    return scryptSync(password, 'rwa-wallet-salt', 32);
  }
}
