/**
 * MPC Wallet Service
 *
 * 使用 MPC 2-of-3 协议生成三链钱包地址
 * 并对地址进行签名验证
 *
 * 调用路径: identity-service → mpc-service → mpc-system
 */

import { Injectable, Logger } from '@nestjs/common';
import { createHash } from 'crypto';
import { MpcClientService } from './mpc-client.service';

export interface MpcWalletGenerationParams {
  userId: string;
  username: string; // 用户名 (用于 MPC keygen)
  deviceId: string;
}

export interface ChainWalletInfo {
  chainType: 'KAVA' | 'DST' | 'BSC';
  address: string;
  publicKey: string;
  addressDigest: string;
  signature: string; // 64 bytes hex (R + S)
}

export interface MpcWalletGenerationResult {
  publicKey: string; // MPC 公钥
  delegateShare: string; // delegate share (加密的用户分片)
  serverParties: string[]; // 服务器 party IDs
  wallets: ChainWalletInfo[]; // 三条链的钱包信息
  sessionId: string; // MPC 会话ID
}

@Injectable()
export class MpcWalletService {
  private readonly logger = new Logger(MpcWalletService.name);

  // 三条链的地址生成配置
  private readonly chainConfigs = {
    BSC: {
      name: 'Binance Smart Chain',
      prefix: '0x',
      derivationPath: "m/44'/60'/0'/0/0", // EVM 兼容链
      addressType: 'evm' as const,
    },
    KAVA: {
      name: 'Kava EVM',
      prefix: '0x',
      derivationPath: "m/44'/60'/0'/0/0", // Kava EVM 使用以太坊兼容地址
      addressType: 'evm' as const,
    },
    DST: {
      name: 'Durian Star Token',
      prefix: 'dst', // Cosmos Bech32 前缀
      derivationPath: "m/44'/118'/0'/0/0", // Cosmos 标准路径
      addressType: 'cosmos' as const,
    },
  };

  constructor(private readonly mpcClient: MpcClientService) {}

  /**
   * 使用 MPC 2-of-3 生成三链钱包
   *
   * 流程:
   * 1. 生成 MPC 密钥 (2-of-3)
   * 2. 从公钥派生三条链的地址
   * 3. 计算地址摘要
   * 4. 使用 MPC 签名对摘要进行签名
   * 5. 返回完整的钱包信息
   */
  async generateMpcWallet(
    params: MpcWalletGenerationParams,
  ): Promise<MpcWalletGenerationResult> {
    this.logger.log(
      `Generating MPC wallet for user=${params.userId}, username=${params.username}`,
    );

    // Step 1: 生成 MPC 密钥
    const keygenResult = await this.mpcClient.executeKeygen({
      sessionId: this.mpcClient.generateSessionId(),
      username: params.username,
      threshold: 1, // t in t-of-n (2-of-3 means t=1)
      totalParties: 3,
      requireDelegate: true,
    });

    this.logger.log(
      `MPC keygen completed: publicKey=${keygenResult.publicKey}`,
    );

    // Step 2: 从公钥派生三条链的地址
    const walletAddresses = await this.deriveChainAddresses(
      keygenResult.publicKey,
    );

    // Step 3: 计算地址摘要
    const addressDigest = this.computeAddressDigest(walletAddresses);

    // Step 4: 使用 MPC 签名对摘要进行签名
    const signingResult = await this.mpcClient.executeSigning({
      username: params.username,
      messageHash: addressDigest,
    });

    this.logger.log(
      `MPC signing completed: signature=${signingResult.signature.slice(0, 16)}...`,
    );

    // Step 5: 构建钱包信息
    const wallets: ChainWalletInfo[] = walletAddresses.map((wa) => ({
      chainType: wa.chainType as 'KAVA' | 'DST' | 'BSC',
      address: wa.address,
      publicKey: keygenResult.publicKey,
      addressDigest: this.computeSingleAddressDigest(wa.address, wa.chainType),
      signature: signingResult.signature,
    }));

    return {
      publicKey: keygenResult.publicKey,
      delegateShare: keygenResult.delegateShare.encryptedShare,
      serverParties: keygenResult.serverParties,
      wallets,
      sessionId: keygenResult.sessionId,
    };
  }

  /**
   * 验证钱包地址签名
   *
   * 用于检测地址是否被篡改
   *
   * @param address 钱包地址
   * @param chainType 链类型
   * @param publicKey 公钥 (hex)
   * @param signature 签名 (64 bytes hex: R + S)
   */
  async verifyWalletSignature(
    address: string,
    chainType: string,
    publicKey: string,
    signature: string,
  ): Promise<boolean> {
    try {
      const { ethers } = await import('ethers');

      // 签名格式: R (32 bytes) + S (32 bytes) = 64 bytes hex
      if (signature.length !== 128) {
        this.logger.error(
          `Invalid signature length: ${signature.length}, expected 128`,
        );
        return false;
      }

      const r = '0x' + signature.slice(0, 64);
      const s = '0x' + signature.slice(64, 128);

      // 计算地址摘要
      const digest = this.computeSingleAddressDigest(address, chainType);
      const digestBytes = Buffer.from(digest, '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() ===
            publicKey.toLowerCase()
          ) {
            return true;
          }
        } catch {
          // 尝试下一个 v 值
        }
      }

      return false;
    } catch (error) {
      this.logger.error(`Signature verification failed: ${error.message}`);
      return false;
    }
  }

  /**
   * 从 MPC 公钥派生三条链的地址
   *
   * - BSC/KAVA: EVM 地址 (keccak256)
   * - DST: Cosmos Bech32 地址 (ripemd160(sha256))
   */
  private async deriveChainAddresses(
    publicKey: string,
  ): Promise<{ chainType: string; address: string }[]> {
    const { ethers } = await import('ethers');
    const { bech32 } = await import('bech32');

    // MPC 公钥 (压缩格式，33 bytes)
    const pubKeyHex = publicKey.startsWith('0x') ? publicKey : '0x' + publicKey;
    const compressedPubKeyBytes = Buffer.from(
      pubKeyHex.replace('0x', ''),
      'hex',
    );

    // 解压公钥 (如果是压缩格式)
    let uncompressedPubKey: string;
    if (pubKeyHex.length === 68) {
      // 压缩格式 (33 bytes = 66 hex chars + 0x)
      uncompressedPubKey = ethers.SigningKey.computePublicKey(pubKeyHex, false);
    } else {
      uncompressedPubKey = pubKeyHex;
    }

    // ===== EVM 地址派生 (BSC, KAVA) =====
    // 地址 = keccak256(公钥[1:])[12:]
    const pubKeyBytes = Buffer.from(uncompressedPubKey.slice(4), 'hex'); // 去掉 0x04 前缀
    const addressHash = ethers.keccak256(pubKeyBytes);
    const evmAddress = ethers.getAddress('0x' + addressHash.slice(-40));

    // ===== Cosmos 地址派生 (DST) =====
    // 地址 = bech32(prefix, ripemd160(sha256(compressed_pubkey)))
    const sha256Hash = createHash('sha256')
      .update(compressedPubKeyBytes)
      .digest();
    const ripemd160Hash = createHash('ripemd160').update(sha256Hash).digest();
    const dstAddress = bech32.encode(
      this.chainConfigs.DST.prefix,
      bech32.toWords(ripemd160Hash),
    );

    return [
      { chainType: 'BSC', address: evmAddress },
      { chainType: 'KAVA', address: evmAddress },
      { chainType: 'DST', address: dstAddress },
    ];
  }

  /**
   * 计算三个地址的联合摘要
   *
   * digest = SHA256(BSC地址 + KAVA地址 + DST地址)
   */
  private computeAddressDigest(
    addresses: { chainType: string; address: string }[],
  ): string {
    // 按链类型排序以确保一致性
    const sortedAddresses = [...addresses].sort((a, b) =>
      a.chainType.localeCompare(b.chainType),
    );

    // 拼接地址
    const concatenated = sortedAddresses
      .map((a) => a.address.toLowerCase())
      .join('');

    // 计算 SHA256 摘要
    return createHash('sha256').update(concatenated).digest('hex');
  }

  /**
   * 计算单个地址的摘要
   */
  private computeSingleAddressDigest(
    address: string,
    chainType: string,
  ): string {
    const message = `${chainType}:${address.toLowerCase()}`;
    return createHash('sha256').update(message).digest('hex');
  }

  /**
   * 获取所有支持的链类型
   */
  getSupportedChains(): string[] {
    return Object.keys(this.chainConfigs);
  }
}
