/**
 * MPC Signing Client
 *
 * 直接调用 mpc-system 的 account-service (port 4000) 进行 MPC 签名
 * 用于热钱包和做市商钱包的 ERC20 转账签名
 *
 * 签名流程:
 * 1. POST /api/v1/mpc/sign → 创建签名会话
 * 2. GET /api/v1/mpc/sessions/{session_id} → 轮询签名结果
 */

import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { HttpService } from '@nestjs/axios';
import { JwtService } from '@nestjs/jwt';
import { randomUUID } from 'crypto';
import { firstValueFrom } from 'rxjs';

export interface CreateSigningInput {
  username: string;
  messageHash: string;
}

export interface SigningResult {
  sessionId: string;
  status: string;
  signature?: string;
}

// MPC 签名请求 Topic (保留导出以避免外部引用报错)
export const MPC_SIGNING_TOPIC = 'mining_mpc.SigningRequested';

@Injectable()
export class MpcSigningClient {
  private readonly logger = new Logger(MpcSigningClient.name);
  // C2C Bot 热钱包
  private readonly hotWalletUsername: string;
  private readonly hotWalletAddress: string;
  // eUSDT (积分股) 做市商钱包
  private readonly eusdtMarketMakerUsername: string;
  private readonly eusdtMarketMakerAddress: string;
  // fUSDT (积分值) 做市商钱包
  private readonly fusdtMarketMakerUsername: string;
  private readonly fusdtMarketMakerAddress: string;
  // 100亿销毁池钱包
  private readonly burnPoolUsername: string;
  private readonly burnPoolAddress: string;
  // 200万挖矿池钱包
  private readonly miningPoolUsername: string;
  private readonly miningPoolAddress: string;
  // fUSDT 注入钱包（认种自动转积分值到做市商）
  private readonly fusdtInjectionUsername: string;
  private readonly fusdtInjectionAddress: string;
  // MPC system 配置
  private readonly mpcAccountServiceUrl: string;
  private readonly mpcJwtSecret: string;
  private readonly signingTimeoutMs: number = 300000; // 5 minutes
  private readonly pollingIntervalMs: number = 2000; // 2 seconds

  constructor(
    private readonly configService: ConfigService,
    private readonly httpService: HttpService,
    private readonly jwtService: JwtService,
  ) {
    // C2C Bot 热钱包配置
    this.hotWalletUsername = this.configService.get<string>('C2C_BOT_WALLET_USERNAME', '');
    this.hotWalletAddress = this.configService.get<string>('C2C_BOT_WALLET_ADDRESS', '');
    // eUSDT (积分股) 做市商钱包配置
    this.eusdtMarketMakerUsername = this.configService.get<string>('EUSDT_MARKET_MAKER_USERNAME', '');
    this.eusdtMarketMakerAddress = this.configService.get<string>('EUSDT_MARKET_MAKER_ADDRESS', '');
    // fUSDT (积分值) 做市商钱包配置
    this.fusdtMarketMakerUsername = this.configService.get<string>('FUSDT_MARKET_MAKER_USERNAME', '');
    this.fusdtMarketMakerAddress = this.configService.get<string>('FUSDT_MARKET_MAKER_ADDRESS', '');
    // 100亿销毁池钱包配置
    this.burnPoolUsername = this.configService.get<string>('BURN_POOL_WALLET_USERNAME', '');
    this.burnPoolAddress = this.configService.get<string>('BURN_POOL_WALLET_ADDRESS', '');
    // 200万挖矿池钱包配置
    this.miningPoolUsername = this.configService.get<string>('MINING_POOL_WALLET_USERNAME', '');
    this.miningPoolAddress = this.configService.get<string>('MINING_POOL_WALLET_ADDRESS', '');
    // fUSDT 注入钱包配置（认种自动转积分值到做市商）
    this.fusdtInjectionUsername = this.configService.get<string>('FUSDT_INJECTION_WALLET_USERNAME', '');
    this.fusdtInjectionAddress = this.configService.get<string>('FUSDT_INJECTION_WALLET_ADDRESS', '');
    // MPC system 配置
    this.mpcAccountServiceUrl = this.configService.get<string>('MPC_ACCOUNT_SERVICE_URL', 'http://localhost:4000');
    this.mpcJwtSecret = this.configService.get<string>('MPC_JWT_SECRET', '');

    if (!this.hotWalletUsername) {
      this.logger.warn('[INIT] C2C_BOT_WALLET_USERNAME not configured (C2C Bot disabled)');
    }
    if (!this.hotWalletAddress) {
      this.logger.warn('[INIT] C2C_BOT_WALLET_ADDRESS not configured (C2C Bot disabled)');
    }
    if (!this.eusdtMarketMakerUsername || !this.eusdtMarketMakerAddress) {
      this.logger.warn('[INIT] eUSDT Market Maker not configured');
    }
    if (!this.fusdtMarketMakerUsername || !this.fusdtMarketMakerAddress) {
      this.logger.warn('[INIT] fUSDT Market Maker not configured');
    }
    if (!this.burnPoolUsername || !this.burnPoolAddress) {
      this.logger.warn('[INIT] Burn Pool wallet not configured');
    }
    if (!this.miningPoolUsername || !this.miningPoolAddress) {
      this.logger.warn('[INIT] Mining Pool wallet not configured');
    }
    if (!this.fusdtInjectionUsername || !this.fusdtInjectionAddress) {
      this.logger.warn('[INIT] fUSDT Injection wallet not configured (adoption auto-injection disabled)');
    }
    if (!this.mpcJwtSecret) {
      this.logger.warn('[INIT] MPC_JWT_SECRET not configured - signing will fail');
    }

    this.logger.log(`[INIT] C2C Bot Wallet: ${this.hotWalletAddress || '(not configured)'}`);
    this.logger.log(`[INIT] eUSDT Market Maker: ${this.eusdtMarketMakerAddress || '(not configured)'}`);
    this.logger.log(`[INIT] fUSDT Market Maker: ${this.fusdtMarketMakerAddress || '(not configured)'}`);
    this.logger.log(`[INIT] Burn Pool: ${this.burnPoolAddress || '(not configured)'}`);
    this.logger.log(`[INIT] Mining Pool: ${this.miningPoolAddress || '(not configured)'}`);
    this.logger.log(`[INIT] fUSDT Injection: ${this.fusdtInjectionAddress || '(not configured)'}`);
    this.logger.log(`[INIT] MPC Account Service: ${this.mpcAccountServiceUrl}`);
    this.logger.log(`[INIT] Using HTTP direct call to mpc-system`);
  }

  /**
   * 检查 C2C Bot 热钱包是否已配置
   */
  isConfigured(): boolean {
    return !!this.hotWalletUsername && !!this.hotWalletAddress;
  }

  /**
   * 检查 eUSDT 做市商钱包是否已配置
   */
  isEusdtMarketMakerConfigured(): boolean {
    return !!this.eusdtMarketMakerUsername && !!this.eusdtMarketMakerAddress;
  }

  /**
   * 检查 fUSDT 做市商钱包是否已配置
   */
  isFusdtMarketMakerConfigured(): boolean {
    return !!this.fusdtMarketMakerUsername && !!this.fusdtMarketMakerAddress;
  }

  /**
   * 获取 C2C Bot 热钱包地址
   */
  getHotWalletAddress(): string {
    return this.hotWalletAddress;
  }

  /**
   * 获取 C2C Bot 热钱包用户名
   */
  getHotWalletUsername(): string {
    return this.hotWalletUsername;
  }

  /**
   * 获取 eUSDT 做市商钱包地址
   */
  getEusdtMarketMakerAddress(): string {
    return this.eusdtMarketMakerAddress;
  }

  /**
   * 获取 eUSDT 做市商 MPC 用户名
   */
  getEusdtMarketMakerUsername(): string {
    return this.eusdtMarketMakerUsername;
  }

  /**
   * 获取 fUSDT 做市商钱包地址
   */
  getFusdtMarketMakerAddress(): string {
    return this.fusdtMarketMakerAddress;
  }

  /**
   * 获取 fUSDT 做市商 MPC 用户名
   */
  getFusdtMarketMakerUsername(): string {
    return this.fusdtMarketMakerUsername;
  }

  // ============ 100亿销毁池钱包 ============

  isBurnPoolConfigured(): boolean {
    return !!this.burnPoolUsername && !!this.burnPoolAddress;
  }

  getBurnPoolAddress(): string {
    return this.burnPoolAddress;
  }

  getBurnPoolUsername(): string {
    return this.burnPoolUsername;
  }

  async signMessageAsBurnPool(messageHash: string): Promise<string> {
    if (!this.burnPoolUsername) {
      throw new Error('Burn Pool MPC username not configured');
    }
    return this.signMessageWithUsername(this.burnPoolUsername, messageHash);
  }

  // ============ 200万挖矿池钱包 ============

  isMiningPoolConfigured(): boolean {
    return !!this.miningPoolUsername && !!this.miningPoolAddress;
  }

  getMiningPoolAddress(): string {
    return this.miningPoolAddress;
  }

  getMiningPoolUsername(): string {
    return this.miningPoolUsername;
  }

  async signMessageAsMiningPool(messageHash: string): Promise<string> {
    if (!this.miningPoolUsername) {
      throw new Error('Mining Pool MPC username not configured');
    }
    return this.signMessageWithUsername(this.miningPoolUsername, messageHash);
  }

  // ============ fUSDT 注入钱包（认种自动转积分值到做市商） ============

  isFusdtInjectionConfigured(): boolean {
    return !!this.fusdtInjectionUsername && !!this.fusdtInjectionAddress;
  }

  getFusdtInjectionAddress(): string {
    return this.fusdtInjectionAddress;
  }

  getFusdtInjectionUsername(): string {
    return this.fusdtInjectionUsername;
  }

  async signMessageAsFusdtInjection(messageHash: string): Promise<string> {
    if (!this.fusdtInjectionUsername) {
      throw new Error('fUSDT Injection MPC username not configured');
    }
    return this.signMessageWithUsername(this.fusdtInjectionUsername, messageHash);
  }

  /**
   * 签名消息（使用 C2C Bot 热钱包）
   *
   * @param messageHash 要签名的消息哈希 (hex string with 0x prefix)
   * @returns 签名结果 (hex string)
   */
  async signMessage(messageHash: string): Promise<string> {
    if (!this.hotWalletUsername) {
      throw new Error('Hot wallet username not configured');
    }
    return this.signMessageWithUsername(this.hotWalletUsername, messageHash);
  }

  /**
   * 使用 eUSDT 做市商钱包签名消息
   *
   * @param messageHash 要签名的消息哈希 (hex string with 0x prefix)
   * @returns 签名结果 (hex string)
   */
  async signMessageAsEusdtMarketMaker(messageHash: string): Promise<string> {
    if (!this.eusdtMarketMakerUsername) {
      throw new Error('eUSDT Market Maker MPC username not configured');
    }
    return this.signMessageWithUsername(this.eusdtMarketMakerUsername, messageHash);
  }

  /**
   * 使用 fUSDT 做市商钱包签名消息
   *
   * @param messageHash 要签名的消息哈希 (hex string with 0x prefix)
   * @returns 签名结果 (hex string)
   */
  async signMessageAsFusdtMarketMaker(messageHash: string): Promise<string> {
    if (!this.fusdtMarketMakerUsername) {
      throw new Error('fUSDT Market Maker MPC username not configured');
    }
    return this.signMessageWithUsername(this.fusdtMarketMakerUsername, messageHash);
  }

  /**
   * 使用指定用户名签名消息（HTTP 直调 mpc-system）
   *
   * @param username MPC 用户名
   * @param messageHash 要签名的消息哈希 (hex string with 0x prefix)
   * @returns 签名结果 (hex string)
   */
  async signMessageWithUsername(username: string, messageHash: string): Promise<string> {
    this.logger.log(`[SIGN] Starting MPC signing for: ${messageHash.slice(0, 16)}... (username: ${username})`);

    if (!username) {
      throw new Error('MPC username not provided');
    }

    if (!this.mpcJwtSecret) {
      throw new Error('MPC_JWT_SECRET not configured');
    }

    // Step 1: 创建签名会话
    const createUrl = `${this.mpcAccountServiceUrl}/api/v1/mpc/sign`;
    const headers = this.getMpcAuthHeaders();

    this.logger.log(`[SIGN] POST ${createUrl}`);

    const createResponse = await firstValueFrom(
      this.httpService.post<{
        session_id: string;
        status: string;
        session_type?: string;
        username?: string;
        message_hash?: string;
      }>(
        createUrl,
        { username, message_hash: messageHash.startsWith('0x') ? messageHash.slice(2) : messageHash },
        { headers, timeout: 30000 },
      ),
    );

    const sessionId = createResponse.data.session_id;
    this.logger.log(`[SIGN] Session created: ${sessionId}, status: ${createResponse.data.status}`);

    // Step 2: 轮询签名结果
    const signature = await this.pollSigningStatus(sessionId);
    this.logger.log(`[SIGN] Signature obtained: ${signature.slice(0, 20)}...`);
    return signature;
  }

  /**
   * 轮询签名会话状态直到完成或超时
   */
  private async pollSigningStatus(sessionId: string): Promise<string> {
    const statusUrl = `${this.mpcAccountServiceUrl}/api/v1/mpc/sessions/${sessionId}`;
    const maxAttempts = Math.ceil(this.signingTimeoutMs / this.pollingIntervalMs);

    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
      await this.delay(this.pollingIntervalMs);

      const response = await firstValueFrom(
        this.httpService.get<{
          session_id: string;
          status: string;
          session_type?: string;
          completed_parties?: number;
          total_parties?: number;
          signature?: string;
        }>(statusUrl, {
          headers: this.getMpcAuthHeaders(),
          timeout: 10000,
        }),
      );

      const { status, signature } = response.data;

      if (attempt % 5 === 0 || status !== 'pending') {
        this.logger.log(`[POLL] Attempt ${attempt}/${maxAttempts}: status=${status}`);
      }

      if (status === 'completed') {
        if (!signature) {
          throw new Error('Signing completed but no signature returned');
        }
        return signature;
      }

      if (status === 'failed' || status === 'expired') {
        throw new Error(`MPC signing ${status}: sessionId=${sessionId}`);
      }
    }

    throw new Error(`MPC signing timeout after ${this.signingTimeoutMs}ms`);
  }

  /**
   * 生成 mpc-system 认证 JWT token
   */
  private generateMpcAccessToken(): string {
    const now = Math.floor(Date.now() / 1000);
    const payload = {
      jti: randomUUID(),
      iss: 'mining-blockchain-service',
      sub: 'system',
      username: 'mining-blockchain-service',
      token_type: 'access',
      iat: now,
      nbf: now,
      exp: now + 24 * 60 * 60,
    };
    return this.jwtService.sign(payload, {
      secret: this.mpcJwtSecret,
      algorithm: 'HS256' as const,
    });
  }

  /**
   * 获取 mpc-system 认证请求头
   */
  private getMpcAuthHeaders(): Record<string, string> {
    const token = this.generateMpcAccessToken();
    return {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
    };
  }

  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}
