/**
 * Recovery Mnemonic Adapter
 *
 * 生成与钱包公钥关联的恢复助记词
 * 支持挂失和更换功能
 */

import { Injectable, Logger } from '@nestjs/common';
import { validateMnemonic, entropyToMnemonic } from '@scure/bip39';
import { wordlist } from '@scure/bip39/wordlists/english';
import { createHash, createCipheriv, createDecipheriv, randomBytes } from 'crypto';
import { ConfigService } from '@nestjs/config';
import * as bcrypt from 'bcrypt';

export interface GenerateMnemonicParams {
  userId: string;
  publicKey: string;  // 钱包公钥 (hex)
}

export interface GenerateMnemonicResult {
  mnemonic: string;             // 12词助记词 (明文，仅首次返回)
  encryptedMnemonic: string;    // 加密的助记词
  mnemonicHash: string;         // 助记词哈希 (用于验证)
  publicKey: string;            // 关联的公钥
}

export interface VerifyMnemonicResult {
  valid: boolean;
  message?: string;
}

@Injectable()
export class RecoveryMnemonicAdapter {
  private readonly logger = new Logger(RecoveryMnemonicAdapter.name);
  private readonly encryptionKey: Buffer;

  constructor(private readonly configService: ConfigService) {
    // 从环境变量获取加密密钥
    const key = this.configService.get<string>('MNEMONIC_ENCRYPTION_KEY');
    if (key) {
      this.encryptionKey = createHash('sha256').update(key).digest();
    } else {
      this.logger.warn('MNEMONIC_ENCRYPTION_KEY not set, using development key');
      this.encryptionKey = createHash('sha256').update('dev-mnemonic-key-do-not-use-in-production').digest();
    }
  }

  /**
   * 生成与钱包公钥关联的恢复助记词
   *
   * 生成逻辑：
   * 1. 用公钥 + 随机数生成熵
   * 2. 从熵生成 12 词 BIP39 助记词
   * 3. 加密存储
   */
  async generateMnemonic(params: GenerateMnemonicParams): Promise<GenerateMnemonicResult> {
    const { userId, publicKey } = params;
    this.logger.log(`Generating recovery mnemonic for user=${userId}, publicKey=${publicKey.slice(0, 16)}...`);

    // 生成随机熵 (128 bits = 16 bytes for 12 words)
    const randomEntropy = randomBytes(16);
    const publicKeyBytes = Buffer.from(publicKey.replace('0x', ''), 'hex');

    // 混合熵: SHA256(randomEntropy + publicKey + timestamp)
    const timestampBuffer = Buffer.alloc(8);
    timestampBuffer.writeBigInt64BE(BigInt(Date.now()));

    const mixedEntropyFull = createHash('sha256')
      .update(randomEntropy)
      .update(publicKeyBytes)
      .update(timestampBuffer)
      .digest();

    // 取前 16 bytes (128 bits) 作为 BIP39 熵
    const entropy = mixedEntropyFull.slice(0, 16);

    // 生成 12 词助记词
    const mnemonic = entropyToMnemonic(entropy, wordlist);

    if (!validateMnemonic(mnemonic, wordlist)) {
      throw new Error('Generated mnemonic validation failed');
    }

    // 加密助记词
    const encryptedMnemonic = this.encryptMnemonic(mnemonic);

    // 计算助记词哈希 (用于验证，不可逆，使用 bcrypt)
    const mnemonicHash = await this.hashMnemonic(mnemonic);

    this.logger.log(`Recovery mnemonic generated: hash=${mnemonicHash.slice(0, 16)}...`);

    return {
      mnemonic,
      encryptedMnemonic,
      mnemonicHash,
      publicKey,
    };
  }

  /**
   * 验证助记词是否正确 (异步，使用 bcrypt)
   */
  async verifyMnemonic(mnemonic: string, expectedHash: string): Promise<VerifyMnemonicResult> {
    if (!validateMnemonic(mnemonic, wordlist)) {
      return { valid: false, message: 'Invalid mnemonic format' };
    }

    // 兼容旧的 SHA256 hash 和新的 bcrypt hash
    if (expectedHash.startsWith('$2')) {
      // bcrypt hash
      const isValid = await bcrypt.compare(mnemonic, expectedHash);
      if (!isValid) {
        return { valid: false, message: 'Mnemonic does not match' };
      }
    } else {
      // 旧的 SHA256 hash (兼容性)
      const hash = this.hashMnemonicSha256(mnemonic);
      if (hash !== expectedHash) {
        return { valid: false, message: 'Mnemonic does not match' };
      }
    }

    return { valid: true };
  }

  /**
   * 解密助记词
   */
  decryptMnemonic(encryptedMnemonic: string): string {
    try {
      const data = Buffer.from(encryptedMnemonic, 'base64');
      const iv = data.slice(0, 16);
      const encrypted = data.slice(16);

      const decipher = createDecipheriv('aes-256-cbc', this.encryptionKey, iv);
      let decrypted = decipher.update(encrypted);
      decrypted = Buffer.concat([decrypted, decipher.final()]);

      return decrypted.toString('utf8');
    } catch (error) {
      this.logger.error(`Failed to decrypt mnemonic: ${error.message}`);
      throw new Error('Failed to decrypt mnemonic');
    }
  }

  /**
   * 加密助记词
   */
  private encryptMnemonic(mnemonic: string): string {
    const iv = randomBytes(16);
    const cipher = createCipheriv('aes-256-cbc', this.encryptionKey, iv);

    let encrypted = cipher.update(mnemonic, 'utf8');
    encrypted = Buffer.concat([encrypted, cipher.final()]);

    return Buffer.concat([iv, encrypted]).toString('base64');
  }

  /**
   * 计算助记词哈希 (使用 bcrypt，抗暴力破解)
   */
  private async hashMnemonic(mnemonic: string): Promise<string> {
    // bcrypt rounds = 12, 足够安全且不会太慢
    const hash = await bcrypt.hash(mnemonic, 12);
    return hash;
  }

  /**
   * SHA256 哈希 (兼容旧数据)
   */
  private hashMnemonicSha256(mnemonic: string): string {
    const hash1 = createHash('sha256').update(mnemonic).digest();
    const hash2 = createHash('sha256').update(hash1).digest();
    return hash2.toString('hex');
  }
}
