import { Injectable, Logger, BadRequestException, TooManyRequestsException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JsonRpcProvider, Wallet, verifyTypedData } from 'ethers';
import { NonceManagerService } from '../nonce/nonce-manager.service';
import { AccountingService } from '../accounting/accounting.service';
import { MetaTransaction, RelayResult } from '../../common/interfaces/relay.interfaces';

@Injectable()
export class RelayService {
  private readonly logger = new Logger(RelayService.name);
  private provider: JsonRpcProvider;
  private relayerWallet: Wallet;
  private userRateLimit: number;

  constructor(
    private config: ConfigService,
    private nonceManager: NonceManagerService,
    private accounting: AccountingService,
  ) {
    this.provider = new JsonRpcProvider(this.config.get('RPC_URL') || 'http://localhost:8545');
    const privateKey = this.config.get('RELAYER_PRIVATE_KEY');
    if (privateKey) {
      this.relayerWallet = new Wallet(privateKey, this.provider);
    }
    this.userRateLimit = parseInt(this.config.get('USER_RATE_LIMIT') || '50', 10);
  }

  /** 接收用户的 meta-transaction，代付 Gas 广播 */
  async relay(metaTx: MetaTransaction): Promise<RelayResult> {
    // 1. 熔断检查：单用户每分钟 > 50 笔时触发限流
    const rateCount = await this.nonceManager.incrementUserRate(metaTx.from);
    if (rateCount > this.userRateLimit) {
      throw new TooManyRequestsException(`Rate limit exceeded: ${rateCount}/${this.userRateLimit} per minute`);
    }

    // 2. 验证用户签名（EIP-712）
    const types = {
      MetaTransaction: [
        { name: 'from', type: 'address' },
        { name: 'target', type: 'address' },
        { name: 'calldata', type: 'bytes' },
        { name: 'nonce', type: 'uint256' },
        { name: 'gasLimit', type: 'uint256' },
      ],
    };

    const value = {
      from: metaTx.from,
      target: metaTx.target,
      calldata: metaTx.calldata,
      nonce: metaTx.nonce,
      gasLimit: metaTx.gasLimit,
    };

    const signer = verifyTypedData(metaTx.domain, types, value, metaTx.signature);
    if (signer.toLowerCase() !== metaTx.from.toLowerCase()) {
      throw new BadRequestException('Invalid EIP-712 signature');
    }

    // 3. 防重放：检查 nonce
    if (await this.nonceManager.isNonceUsed(metaTx.from, metaTx.nonce)) {
      throw new BadRequestException('Nonce already used');
    }

    // 4. 构造链上交易（Relayer 为 tx.origin，Gas 由 Relayer 钱包支付）
    const relayerNonce = await this.nonceManager.next(this.relayerWallet.address);
    const tx = await this.relayerWallet.sendTransaction({
      to: metaTx.target,
      data: metaTx.calldata,
      gasLimit: BigInt(metaTx.gasLimit),
      nonce: relayerNonce,
    });

    // 5. 标记 nonce 已使用
    await this.nonceManager.markNonceUsed(metaTx.from, metaTx.nonce);

    // 6. Gas 费用记账
    const receipt = await tx.wait();
    if (receipt) {
      await this.accounting.recordGasSpent(metaTx.from, receipt.gasUsed.toString());
    }

    this.logger.log(`Relayed tx for ${metaTx.from} → ${metaTx.target}, hash: ${tx.hash}`);

    return {
      txHash: tx.hash,
      from: metaTx.from,
      target: metaTx.target,
      gasUsed: receipt?.gasUsed.toString() || '0',
      status: receipt?.status === 1 ? 'success' : 'failed',
    };
  }

  /** 获取 Relayer 钱包余额 */
  async getRelayerBalance(): Promise<string> {
    if (!this.relayerWallet) return '0';
    const balance = await this.provider.getBalance(this.relayerWallet.address);
    return balance.toString();
  }
}
