import { HDKey } from '@scure/bip32';
import { createHash } from 'crypto';
import { bech32 } from 'bech32';
import { Wallet } from 'ethers';
import { DomainError } from '@/shared/exceptions/domain.exception';
import {
  AddressId,
  UserId,
  ChainType,
  CHAIN_CONFIG,
  AddressStatus,
  Mnemonic,
  MnemonicEncryption,
} from '@/domain/value-objects';

/**
 * MPC 签名信息
 * 64 bytes hex (R 32 bytes + S 32 bytes)
 */
export type MpcSignature = string;

export class WalletAddress {
  private readonly _addressId: AddressId;
  private readonly _userId: UserId;
  private readonly _chainType: ChainType;
  private readonly _address: string;
  private readonly _publicKey: string; // MPC 公钥
  private readonly _addressDigest: string; // 地址摘要
  private readonly _mpcSignature: MpcSignature; // MPC 签名
  private _status: AddressStatus;
  private readonly _boundAt: Date;

  get addressId(): AddressId {
    return this._addressId;
  }
  get userId(): UserId {
    return this._userId;
  }
  get chainType(): ChainType {
    return this._chainType;
  }
  get address(): string {
    return this._address;
  }
  get publicKey(): string {
    return this._publicKey;
  }
  get addressDigest(): string {
    return this._addressDigest;
  }
  get mpcSignature(): MpcSignature {
    return this._mpcSignature;
  }
  get status(): AddressStatus {
    return this._status;
  }
  get boundAt(): Date {
    return this._boundAt;
  }

  private constructor(
    addressId: AddressId,
    userId: UserId,
    chainType: ChainType,
    address: string,
    publicKey: string,
    addressDigest: string,
    mpcSignature: MpcSignature,
    status: AddressStatus,
    boundAt: Date,
  ) {
    this._addressId = addressId;
    this._userId = userId;
    this._chainType = chainType;
    this._address = address;
    this._publicKey = publicKey;
    this._addressDigest = addressDigest;
    this._mpcSignature = mpcSignature;
    this._status = status;
    this._boundAt = boundAt;
  }

  /**
   * 创建 MPC 钱包地址
   *
   * @param params 包含 MPC 签名验证信息的参数
   */
  static createMpc(params: {
    userId: UserId;
    chainType: ChainType;
    address: string;
    publicKey: string;
    addressDigest: string;
    signature: MpcSignature;
  }): WalletAddress {
    if (!this.validateEvmAddress(params.address)) {
      throw new DomainError(`${params.chainType}地址格式错误`);
    }
    return new WalletAddress(
      AddressId.generate(),
      params.userId,
      params.chainType,
      params.address,
      params.publicKey,
      params.addressDigest,
      params.signature,
      AddressStatus.ACTIVE,
      new Date(),
    );
  }

  /**
   * 从数据库重建实体
   */
  static reconstruct(params: {
    addressId: string;
    userId: string;
    chainType: ChainType;
    address: string;
    publicKey: string;
    addressDigest: string;
    mpcSignature: string; // 64 bytes hex
    status: AddressStatus;
    boundAt: Date;
  }): WalletAddress {
    return new WalletAddress(
      AddressId.create(params.addressId),
      UserId.create(params.userId),
      params.chainType,
      params.address,
      params.publicKey,
      params.addressDigest,
      params.mpcSignature,
      params.status,
      params.boundAt,
    );
  }

  disable(): void {
    this._status = AddressStatus.DISABLED;
  }

  enable(): void {
    this._status = AddressStatus.ACTIVE;
  }

  /**
   * 验证签名是否有效
   * 用于检测地址是否被篡改
   */
  async verifySignature(): Promise<boolean> {
    try {
      const { ethers } = await import('ethers');

      // 计算预期的摘要
      const expectedDigest = this.computeDigest();
      if (expectedDigest !== this._addressDigest) {
        return false;
      }

      // 签名格式: R (32 bytes) + S (32 bytes) = 64 bytes hex = 128 chars
      if (this._mpcSignature.length !== 128) {
        return false;
      }

      const r = '0x' + this._mpcSignature.slice(0, 64);
      const s = '0x' + this._mpcSignature.slice(64, 128);
      const digestBytes = Buffer.from(this._addressDigest, 'hex');

      // 尝试两种 recovery id
      for (const v of [27, 28]) {
        try {
          const sig = ethers.Signature.from({ r, s, v });
          const recoveredPubKey = ethers.SigningKey.recoverPublicKey(
            digestBytes,
            sig,
          );
          const compressedRecovered = ethers.SigningKey.computePublicKey(
            recoveredPubKey,
            true,
          );

          if (
            compressedRecovered.slice(2).toLowerCase() ===
            this._publicKey.toLowerCase()
          ) {
            return true;
          }
        } catch {
          // 尝试下一个 v 值
        }
      }

      return false;
    } catch {
      return false;
    }
  }

  /**
   * 计算地址摘要
   */
  private computeDigest(): string {
    const message = `${this._chainType}:${this._address.toLowerCase()}`;
    return createHash('sha256').update(message).digest('hex');
  }

  /**
   * 验证 EVM 地址格式
   */
  private static validateEvmAddress(address: string): boolean {
    return /^0x[a-fA-F0-9]{40}$/.test(address);
  }

  // ==================== 兼容旧版本的方法 (保留但标记为废弃) ====================

  /**
   * 创建钱包地址（简化版，用于从 blockchain-service 接收地址）
   */
  static create(params: {
    userId: UserId;
    chainType: ChainType;
    address: string;
    publicKey?: string; // 公钥
  }): WalletAddress {
    if (!this.validateAddress(params.chainType, params.address)) {
      throw new DomainError(`${params.chainType}地址格式错误`);
    }
    return new WalletAddress(
      AddressId.generate(),
      params.userId,
      params.chainType,
      params.address,
      params.publicKey || '',
      '',
      '', // empty signature
      AddressStatus.ACTIVE,
      new Date(),
    );
  }

  /**
   * @deprecated MPC 模式下不再使用助记词
   */
  static createFromMnemonic(params: {
    userId: UserId;
    chainType: ChainType;
    mnemonic: Mnemonic;
    encryptionKey: string;
  }): WalletAddress {
    const address = this.deriveAddress(params.chainType, params.mnemonic);
    return new WalletAddress(
      AddressId.generate(),
      params.userId,
      params.chainType,
      address,
      '',
      '',
      '', // empty signature
      AddressStatus.ACTIVE,
      new Date(),
    );
  }

  private static deriveAddress(
    chainType: ChainType,
    mnemonic: Mnemonic,
  ): string {
    const seed = mnemonic.toSeed();
    const config = CHAIN_CONFIG[chainType];

    switch (chainType) {
      case ChainType.KAVA:
      case ChainType.DST:
        return this.deriveCosmosAddress(
          Buffer.from(seed),
          config.derivationPath,
          config.prefix,
        );
      case ChainType.BSC:
        return this.deriveEVMAddress(Buffer.from(seed), config.derivationPath);
      default:
        throw new DomainError(`不支持的链类型: ${chainType}`);
    }
  }

  private static deriveCosmosAddress(
    seed: Buffer,
    path: string,
    prefix: string,
  ): string {
    const hdkey = HDKey.fromMasterSeed(seed);
    const childKey = hdkey.derive(path);
    if (!childKey.publicKey) throw new DomainError('无法派生公钥');

    const hash = createHash('sha256').update(childKey.publicKey).digest();
    const addressHash = createHash('ripemd160').update(hash).digest();
    const words = bech32.toWords(addressHash);
    return bech32.encode(prefix, words);
  }

  private static deriveEVMAddress(seed: Buffer, path: string): string {
    const hdkey = HDKey.fromMasterSeed(seed);
    const childKey = hdkey.derive(path);
    if (!childKey.privateKey) throw new DomainError('无法派生私钥');

    const wallet = new Wallet(Buffer.from(childKey.privateKey).toString('hex'));
    return wallet.address;
  }

  private static validateAddress(
    chainType: ChainType,
    address: string,
  ): boolean {
    switch (chainType) {
      case ChainType.KAVA:
      case ChainType.BSC:
        // KAVA 和 BSC 都使用 EVM 地址格式
        return /^0x[a-fA-F0-9]{40}$/.test(address);
      case ChainType.DST:
        // DST 使用 Cosmos bech32 格式
        return /^dst1[a-z0-9]{38}$/.test(address);
      default:
        return false;
    }
  }
}
