/**
 * Kava EVM 交易构建工具
 * 用于构建 EIP-1559 交易并计算签名哈希
 * 支持原生 KAVA 和 ERC-20 代币 (绿积分) 转账
 */

// Kava EVM Chain IDs
export const KAVA_CHAIN_ID = {
  mainnet: 2222,
  testnet: 2221,
};

// RPC URLs
export const KAVA_RPC_URL = {
  mainnet: 'https://evm.kava.io',
  testnet: 'https://evm.testnet.kava.io',
};

// Token types
export type TokenType = 'KAVA' | 'GREEN_POINTS' | 'ENERGY_POINTS' | 'FUTURE_POINTS';

// ERC-20 通用函数选择器
export const ERC20_SELECTORS = {
  balanceOf: '0x70a08231',    // balanceOf(address)
  transfer: '0xa9059cbb',     // transfer(address,uint256)
  approve: '0x095ea7b3',      // approve(address,uint256)
  allowance: '0xdd62ed3e',    // allowance(address,address)
  totalSupply: '0x18160ddd',  // totalSupply()
};

// Green Points (绿积分) Token Configuration - dUSDT
export const GREEN_POINTS_TOKEN = {
  contractAddress: '0xA9F3A35dBa8699c8C681D8db03F0c1A8CEB9D7c3',
  name: '绿积分',
  symbol: 'dUSDT',
  decimals: 6,
  // ERC-20 function selectors (kept for backward compatibility)
  balanceOfSelector: ERC20_SELECTORS.balanceOf,
  transferSelector: ERC20_SELECTORS.transfer,
};

// Energy Points (积分股) Token Configuration - eUSDT
export const ENERGY_POINTS_TOKEN = {
  contractAddress: '0x7C3275D808eFbAE90C06C7E3A9AfDdcAa8563931',
  name: '积分股',
  symbol: 'eUSDT',
  decimals: 6,
};

// Future Points (积分值) Token Configuration - fUSDT
export const FUTURE_POINTS_TOKEN = {
  contractAddress: '0x14dc4f7d3E4197438d058C3D156dd9826A161134',
  name: '积分值',
  symbol: 'fUSDT',
  decimals: 6,
};

// Token configuration utility
export const TOKEN_CONFIG = {
  getContractAddress: (tokenType: TokenType): string | null => {
    switch (tokenType) {
      case 'KAVA':
        return null; // Native token has no contract
      case 'GREEN_POINTS':
        return GREEN_POINTS_TOKEN.contractAddress;
      case 'ENERGY_POINTS':
        return ENERGY_POINTS_TOKEN.contractAddress;
      case 'FUTURE_POINTS':
        return FUTURE_POINTS_TOKEN.contractAddress;
    }
  },
  getDecimals: (tokenType: TokenType): number => {
    switch (tokenType) {
      case 'KAVA':
        return 18;
      case 'GREEN_POINTS':
        return GREEN_POINTS_TOKEN.decimals;
      case 'ENERGY_POINTS':
        return ENERGY_POINTS_TOKEN.decimals;
      case 'FUTURE_POINTS':
        return FUTURE_POINTS_TOKEN.decimals;
    }
  },
  getName: (tokenType: TokenType): string => {
    switch (tokenType) {
      case 'KAVA':
        return 'KAVA';
      case 'GREEN_POINTS':
        return GREEN_POINTS_TOKEN.name;
      case 'ENERGY_POINTS':
        return ENERGY_POINTS_TOKEN.name;
      case 'FUTURE_POINTS':
        return FUTURE_POINTS_TOKEN.name;
    }
  },
  getSymbol: (tokenType: TokenType): string => {
    switch (tokenType) {
      case 'KAVA':
        return 'KAVA';
      case 'GREEN_POINTS':
        return GREEN_POINTS_TOKEN.symbol;
      case 'ENERGY_POINTS':
        return ENERGY_POINTS_TOKEN.symbol;
      case 'FUTURE_POINTS':
        return FUTURE_POINTS_TOKEN.symbol;
    }
  },
  isERC20: (tokenType: TokenType): boolean => {
    return tokenType !== 'KAVA';
  },
};

// 当前网络配置 (从 localStorage 读取或使用默认值)
export function getCurrentNetwork(): 'mainnet' | 'testnet' {
  if (typeof window !== 'undefined' && window.localStorage) {
    const stored = localStorage.getItem('kava_network');
    if (stored === 'mainnet' || stored === 'testnet') {
      return stored;
    }
  }
  return 'mainnet'; // 默认主网
}

export function getCurrentChainId(): number {
  return KAVA_CHAIN_ID[getCurrentNetwork()];
}

export function getCurrentRpcUrl(): string {
  return KAVA_RPC_URL[getCurrentNetwork()];
}

/**
 * 交易参数接口
 */
export interface TransactionParams {
  to: string;           // 收款地址
  value: string;        // 转账金额 (KAVA 或代币单位, 字符串以支持大数)
  from: string;         // 发送地址
  nonce?: number;       // 可选，自动获取
  gasLimit?: bigint;    // 可选，默认 21000
  maxFeePerGas?: bigint;     // 可选，自动获取
  maxPriorityFeePerGas?: bigint; // 可选，自动获取
  data?: string;        // 可选，合约调用数据
  tokenType?: TokenType; // 可选，默认 KAVA
}

/**
 * 准备好的交易 (包含所有必要字段)
 * 使用 Legacy 交易格式 (Type 0)，因为 KAVA 不支持 EIP-1559
 */
export interface PreparedTransaction {
  chainId: number;
  nonce: number;
  gasPrice: bigint;  // Legacy 使用 gasPrice 而不是 maxFeePerGas
  gasLimit: bigint;
  to: string;
  value: bigint;
  data: string;
  // 用于签名的哈希
  signHash: string;
  // 原始交易数据 (用于签名后广播)
  rawTxForSigning: string;
  // 为了兼容性保留这些字段
  maxPriorityFeePerGas?: bigint;
  maxFeePerGas?: bigint;
  accessList?: unknown[];
}

/**
 * 将数字转换为十六进制字符串 (带 0x 前缀)
 */
function toHex(value: number | bigint): string {
  const hex = value.toString(16);
  return '0x' + hex;
}

/**
 * 将十六进制字符串转换为 Uint8Array
 */
function hexToBytes(hex: string): Uint8Array {
  const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex;
  if (cleanHex.length === 0) return new Uint8Array(0);
  const bytes = new Uint8Array(cleanHex.length / 2);
  for (let i = 0; i < cleanHex.length; i += 2) {
    bytes[i / 2] = parseInt(cleanHex.substring(i, i + 2), 16);
  }
  return bytes;
}

/**
 * 将 Uint8Array 转换为十六进制字符串
 */
function bytesToHex(bytes: Uint8Array): string {
  return Array.from(bytes)
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');
}

/**
 * RLP 编码
 * 参考: https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/
 */
function rlpEncode(input: unknown): Uint8Array {
  if (typeof input === 'string') {
    // 处理十六进制字符串
    if (input.startsWith('0x')) {
      const bytes = hexToBytes(input);
      return rlpEncodeBytes(bytes);
    }
    // 普通字符串
    const bytes = new TextEncoder().encode(input);
    return rlpEncodeBytes(bytes);
  }

  if (typeof input === 'number' || typeof input === 'bigint') {
    if (input === 0 || input === 0n) {
      return rlpEncodeBytes(new Uint8Array(0));
    }
    // 转换为最小字节表示
    let hex = input.toString(16);
    if (hex.length % 2 !== 0) hex = '0' + hex;
    return rlpEncodeBytes(hexToBytes(hex));
  }

  if (input instanceof Uint8Array) {
    return rlpEncodeBytes(input);
  }

  if (Array.isArray(input)) {
    // 编码列表
    const encoded = input.map(item => rlpEncode(item));
    const totalLength = encoded.reduce((acc, item) => acc + item.length, 0);

    if (totalLength <= 55) {
      const result = new Uint8Array(1 + totalLength);
      result[0] = 0xc0 + totalLength;
      let offset = 1;
      for (const item of encoded) {
        result.set(item, offset);
        offset += item.length;
      }
      return result;
    } else {
      const lengthBytes = encodeLength(totalLength);
      const result = new Uint8Array(1 + lengthBytes.length + totalLength);
      result[0] = 0xf7 + lengthBytes.length;
      result.set(lengthBytes, 1);
      let offset = 1 + lengthBytes.length;
      for (const item of encoded) {
        result.set(item, offset);
        offset += item.length;
      }
      return result;
    }
  }

  throw new Error('Unsupported RLP input type');
}

function rlpEncodeBytes(bytes: Uint8Array): Uint8Array {
  if (bytes.length === 1 && bytes[0] < 0x80) {
    // 单字节值直接返回
    return bytes;
  }

  if (bytes.length <= 55) {
    const result = new Uint8Array(1 + bytes.length);
    result[0] = 0x80 + bytes.length;
    result.set(bytes, 1);
    return result;
  }

  const lengthBytes = encodeLength(bytes.length);
  const result = new Uint8Array(1 + lengthBytes.length + bytes.length);
  result[0] = 0xb7 + lengthBytes.length;
  result.set(lengthBytes, 1);
  result.set(bytes, 1 + lengthBytes.length);
  return result;
}

function encodeLength(length: number): Uint8Array {
  let hex = length.toString(16);
  if (hex.length % 2 !== 0) hex = '0' + hex;
  return hexToBytes(hex);
}

/**
 * Keccak-256 哈希 (复用 address.ts 中的实现)
 */
async function keccak256(data: Uint8Array): Promise<Uint8Array> {
  const RC = [
    0x0000000000000001n, 0x0000000000008082n, 0x800000000000808an,
    0x8000000080008000n, 0x000000000000808bn, 0x0000000080000001n,
    0x8000000080008081n, 0x8000000000008009n, 0x000000000000008an,
    0x0000000000000088n, 0x0000000080008009n, 0x000000008000000an,
    0x000000008000808bn, 0x800000000000008bn, 0x8000000000008089n,
    0x8000000000008003n, 0x8000000000008002n, 0x8000000000000080n,
    0x000000000000800an, 0x800000008000000an, 0x8000000080008081n,
    0x8000000000008080n, 0x0000000080000001n, 0x8000000080008008n,
  ];

  const ROTC = [
    [0, 36, 3, 41, 18],
    [1, 44, 10, 45, 2],
    [62, 6, 43, 15, 61],
    [28, 55, 25, 21, 56],
    [27, 20, 39, 8, 14],
  ];

  function rotl64(x: bigint, n: number): bigint {
    return ((x << BigInt(n)) | (x >> BigInt(64 - n))) & 0xffffffffffffffffn;
  }

  function keccakF(state: bigint[][]): void {
    for (let round = 0; round < 24; round++) {
      const C: bigint[] = [];
      for (let x = 0; x < 5; x++) {
        C[x] = state[x][0] ^ state[x][1] ^ state[x][2] ^ state[x][3] ^ state[x][4];
      }
      const D: bigint[] = [];
      for (let x = 0; x < 5; x++) {
        D[x] = C[(x + 4) % 5] ^ rotl64(C[(x + 1) % 5], 1);
      }
      for (let x = 0; x < 5; x++) {
        for (let y = 0; y < 5; y++) {
          state[x][y] ^= D[x];
        }
      }

      const B: bigint[][] = Array(5).fill(null).map(() => Array(5).fill(0n));
      for (let x = 0; x < 5; x++) {
        for (let y = 0; y < 5; y++) {
          B[y][(2 * x + 3 * y) % 5] = rotl64(state[x][y], ROTC[x][y]);
        }
      }

      for (let x = 0; x < 5; x++) {
        for (let y = 0; y < 5; y++) {
          state[x][y] = B[x][y] ^ (~B[(x + 1) % 5][y] & B[(x + 2) % 5][y]);
        }
      }

      state[0][0] ^= RC[round];
    }
  }

  const rate = 136;
  const outputLen = 32;
  const state: bigint[][] = Array(5).fill(null).map(() => Array(5).fill(0n));
  const padded = new Uint8Array(Math.ceil((data.length + 1) / rate) * rate);
  padded.set(data);
  padded[data.length] = 0x01;
  padded[padded.length - 1] |= 0x80;

  for (let i = 0; i < padded.length; i += rate) {
    for (let j = 0; j < rate && i + j < padded.length; j += 8) {
      const x = Math.floor(j / 8) % 5;
      const y = Math.floor(Math.floor(j / 8) / 5);
      let lane = 0n;
      for (let k = 0; k < 8 && i + j + k < padded.length; k++) {
        lane |= BigInt(padded[i + j + k]) << BigInt(k * 8);
      }
      state[x][y] ^= lane;
    }
    keccakF(state);
  }

  const output = new Uint8Array(outputLen);
  for (let i = 0; i < outputLen; i += 8) {
    const x = Math.floor(i / 8) % 5;
    const y = Math.floor(Math.floor(i / 8) / 5);
    const lane = state[x][y];
    for (let k = 0; k < 8 && i + k < outputLen; k++) {
      output[i + k] = Number((lane >> BigInt(k * 8)) & 0xffn);
    }
  }

  return output;
}

/**
 * 将 KAVA 金额转换为 wei (18 位小数)
 */
export function kavaToWei(kava: string): bigint {
  const parts = kava.split('.');
  const whole = BigInt(parts[0] || '0');
  let fraction = parts[1] || '';

  // 补齐或截断到 18 位
  if (fraction.length > 18) {
    fraction = fraction.substring(0, 18);
  } else {
    fraction = fraction.padEnd(18, '0');
  }

  return whole * BigInt(10 ** 18) + BigInt(fraction);
}

/**
 * 将 wei 转换为 KAVA 金额
 */
export function weiToKava(wei: bigint): string {
  const weiStr = wei.toString().padStart(19, '0');
  const whole = weiStr.slice(0, -18) || '0';
  const fraction = weiStr.slice(-18).replace(/0+$/, '');
  return fraction ? `${whole}.${fraction}` : whole;
}

/**
 * 将代币金额转换为最小单位
 * @param amount Human-readable amount
 * @param decimals Token decimals (default 6 for USDT-like tokens)
 */
export function tokenToRaw(amount: string, decimals: number = 6): bigint {
  const parts = amount.split('.');
  const whole = BigInt(parts[0] || '0');
  let fraction = parts[1] || '';

  // 补齐或截断到指定位数
  if (fraction.length > decimals) {
    fraction = fraction.substring(0, decimals);
  } else {
    fraction = fraction.padEnd(decimals, '0');
  }

  return whole * BigInt(10 ** decimals) + BigInt(fraction);
}

/**
 * 将最小单位转换为代币金额
 * @param raw Raw amount in smallest units
 * @param decimals Token decimals (default 6 for USDT-like tokens)
 */
export function rawToToken(raw: bigint, decimals: number = 6): string {
  const rawStr = raw.toString().padStart(decimals + 1, '0');
  const whole = rawStr.slice(0, -decimals) || '0';
  const fraction = rawStr.slice(-decimals).replace(/0+$/, '');
  return fraction ? `${whole}.${fraction}` : whole;
}

/**
 * 将绿积分金额转换为最小单位 (6 decimals)
 * @deprecated Use tokenToRaw(amount, 6) instead
 */
export function greenPointsToRaw(amount: string): bigint {
  return tokenToRaw(amount, GREEN_POINTS_TOKEN.decimals);
}

/**
 * 将最小单位转换为绿积分金额
 * @deprecated Use rawToToken(raw, 6) instead
 */
export function rawToGreenPoints(raw: bigint): string {
  return rawToToken(raw, GREEN_POINTS_TOKEN.decimals);
}

/**
 * 查询 ERC-20 代币余额
 * @param address Wallet address
 * @param contractAddress Token contract address
 * @param decimals Token decimals
 */
export async function fetchERC20Balance(
  address: string,
  contractAddress: string,
  decimals: number = 6
): Promise<string> {
  try {
    const rpcUrl = getCurrentRpcUrl();
    // Encode balanceOf(address) call data
    const paddedAddress = address.toLowerCase().replace('0x', '').padStart(64, '0');
    const callData = ERC20_SELECTORS.balanceOf + paddedAddress;

    const response = await fetch(rpcUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'eth_call',
        params: [
          {
            to: contractAddress,
            data: callData,
          },
          'latest',
        ],
        id: 1,
      }),
    });

    const data = await response.json();
    if (data.result && data.result !== '0x') {
      const balanceRaw = BigInt(data.result);
      return rawToToken(balanceRaw, decimals);
    }
    return '0';
  } catch (error) {
    console.error('Failed to fetch ERC20 balance:', error);
    return '0';
  }
}

/**
 * 查询绿积分 (ERC-20) 余额
 */
export async function fetchGreenPointsBalance(address: string): Promise<string> {
  return fetchERC20Balance(address, GREEN_POINTS_TOKEN.contractAddress, GREEN_POINTS_TOKEN.decimals);
}

/**
 * 查询积分股 (eUSDT) 余额
 */
export async function fetchEnergyPointsBalance(address: string): Promise<string> {
  return fetchERC20Balance(address, ENERGY_POINTS_TOKEN.contractAddress, ENERGY_POINTS_TOKEN.decimals);
}

/**
 * 查询积分值 (fUSDT) 余额
 */
export async function fetchFuturePointsBalance(address: string): Promise<string> {
  return fetchERC20Balance(address, FUTURE_POINTS_TOKEN.contractAddress, FUTURE_POINTS_TOKEN.decimals);
}

/**
 * 查询所有代币余额
 */
export async function fetchAllTokenBalances(address: string): Promise<{
  kava: string;
  greenPoints: string;
  energyPoints: string;
  futurePoints: string;
}> {
  const [greenPoints, energyPoints, futurePoints] = await Promise.all([
    fetchGreenPointsBalance(address),
    fetchEnergyPointsBalance(address),
    fetchFuturePointsBalance(address),
  ]);
  // Note: KAVA balance is fetched separately via eth_getBalance
  return {
    kava: '0', // Caller should fetch KAVA balance separately
    greenPoints,
    energyPoints,
    futurePoints,
  };
}

/**
 * Encode ERC-20 transfer function call
 */
function encodeErc20Transfer(to: string, amount: bigint): string {
  // Function selector: transfer(address,uint256) = 0xa9059cbb
  const selector = ERC20_SELECTORS.transfer;
  // Encode recipient address (padded to 32 bytes)
  const paddedAddress = to.toLowerCase().replace('0x', '').padStart(64, '0');
  // Encode amount (padded to 32 bytes)
  const amountHex = amount.toString(16).padStart(64, '0');
  return selector + paddedAddress + amountHex;
}

/**
 * 通过 RPC 获取账户 nonce
 */
export async function getNonce(address: string): Promise<number> {
  const rpcUrl = getCurrentRpcUrl();
  const response = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_getTransactionCount',
      params: [address, 'pending'],
      id: 1,
    }),
  });

  const data = await response.json();
  if (data.error) {
    throw new Error(`获取 nonce 失败: ${data.error.message}`);
  }
  return parseInt(data.result, 16);
}

/**
 * 通过 RPC 获取当前 gas 价格
 * 使用 eth_gasPrice 方法获取 Legacy 交易的 gasPrice
 */
export async function getGasPrice(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }> {
  const rpcUrl = getCurrentRpcUrl();

  // 使用 eth_gasPrice 获取建议的 gas 价格
  const response = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_gasPrice',
      params: [],
      id: 1,
    }),
  });

  const data = await response.json();
  let gasPrice: bigint;

  if (data.result) {
    gasPrice = BigInt(data.result);
    // 增加 10% 以确保交易能被打包
    gasPrice = gasPrice * 110n / 100n;
  } else {
    // 默认 1 gwei
    gasPrice = BigInt(1000000000);
  }

  // 为了兼容性，同时返回 maxFeePerGas (实际上用作 gasPrice)
  return { maxFeePerGas: gasPrice, maxPriorityFeePerGas: gasPrice };
}

/**
 * 预估 gas 用量
 */
export async function estimateGas(params: { from: string; to: string; value: string; data?: string; tokenType?: TokenType }): Promise<bigint> {
  const rpcUrl = getCurrentRpcUrl();
  const tokenType = params.tokenType || 'KAVA';

  // For token transfers, we need different params
  let txParams: { from: string; to: string; value: string; data?: string };

  if (TOKEN_CONFIG.isERC20(tokenType)) {
    // ERC-20 transfer: to is contract, value is 0, data is transfer call
    const contractAddress = TOKEN_CONFIG.getContractAddress(tokenType);
    const decimals = TOKEN_CONFIG.getDecimals(tokenType);
    const tokenAmount = tokenToRaw(params.value, decimals);
    const transferData = encodeErc20Transfer(params.to, tokenAmount);
    txParams = {
      from: params.from,
      to: contractAddress!,
      value: '0x0',
      data: transferData,
    };
  } else {
    // Native KAVA transfer
    txParams = {
      from: params.from,
      to: params.to,
      value: toHex(kavaToWei(params.value)),
      data: params.data || '0x',
    };
  }

  const response = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_estimateGas',
      params: [txParams],
      id: 1,
    }),
  });

  const data = await response.json();
  if (data.error) {
    // 如果估算失败，使用默认值
    console.warn('Gas 估算失败，使用默认值:', data.error);
    return TOKEN_CONFIG.isERC20(tokenType) ? BigInt(65000) : BigInt(21000);
  }
  return BigInt(data.result);
}

/**
 * 准备 Legacy 交易 (Type 0)
 * KAVA 不支持 EIP-1559，所以使用 Legacy 格式
 * 返回交易数据和待签名的哈希
 * 支持原生 KAVA 和 ERC-20 代币 (绿积分) 转账
 */
export async function prepareTransaction(params: TransactionParams): Promise<PreparedTransaction> {
  const chainId = getCurrentChainId();
  const tokenType = params.tokenType || 'KAVA';

  // 获取或使用提供的参数
  const nonce = params.nonce ?? await getNonce(params.from);
  const gasPriceData = await getGasPrice();
  const gasPrice = params.maxFeePerGas ?? gasPriceData.maxFeePerGas;
  const gasLimit = params.gasLimit ?? await estimateGas({
    from: params.from,
    to: params.to,
    value: params.value,
    data: params.data,
    tokenType,
  });

  // Prepare transaction based on token type
  let toAddress: string;
  let value: bigint;
  let data: string;

  if (TOKEN_CONFIG.isERC20(tokenType)) {
    // ERC-20 token transfer
    // To address is the contract, value is 0
    // Data is transfer(recipient, amount) encoded
    const contractAddress = TOKEN_CONFIG.getContractAddress(tokenType);
    const decimals = TOKEN_CONFIG.getDecimals(tokenType);
    const tokenAmount = tokenToRaw(params.value, decimals);
    toAddress = contractAddress!.toLowerCase();
    value = BigInt(0);
    data = encodeErc20Transfer(params.to, tokenAmount);
  } else {
    // Native KAVA transfer
    toAddress = params.to.toLowerCase();
    value = kavaToWei(params.value);
    data = params.data || '0x';
  }

  // Legacy 交易字段顺序 (EIP-155)
  // [nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0]
  // 最后三个字段用于 EIP-155 replay protection
  const txFields = [
    nonce,
    gasPrice,
    gasLimit,
    toAddress,
    value,
    data,
    chainId,
    0,  // EIP-155: v placeholder
    0,  // EIP-155: r placeholder
  ];

  // RLP 编码交易字段
  const encodedTx = rlpEncode(txFields);

  // 计算签名哈希 (不需要类型前缀，Legacy 交易直接哈希)
  const signHashBytes = await keccak256(encodedTx);
  const signHash = bytesToHex(signHashBytes);

  return {
    chainId,
    nonce,
    gasPrice,
    gasLimit,
    to: toAddress,
    value,
    data,
    signHash,
    rawTxForSigning: bytesToHex(encodedTx),
  };
}

/**
 * 使用签名完成交易并返回可广播的原始交易
 * 使用 Legacy 交易格式 (Type 0)
 */
export function finalizeTransaction(
  preparedTx: PreparedTransaction,
  signature: { r: string; s: string; v: number }
): string {
  // EIP-155: v = chainId * 2 + 35 + recovery_id
  // recovery_id 是 0 或 1
  const v = preparedTx.chainId * 2 + 35 + signature.v;

  // Legacy 签名后的交易字段
  // [nonce, gasPrice, gasLimit, to, value, data, v, r, s]
  const signedTxFields = [
    preparedTx.nonce,
    preparedTx.gasPrice,
    preparedTx.gasLimit,
    preparedTx.to,
    preparedTx.value,
    preparedTx.data,
    v,
    '0x' + signature.r,
    '0x' + signature.s,
  ];

  const encodedSignedTx = rlpEncode(signedTxFields);

  // Legacy 交易不需要类型前缀
  return '0x' + bytesToHex(encodedSignedTx);
}

/**
 * 广播已签名的交易
 */
export async function broadcastTransaction(signedTx: string): Promise<string> {
  const rpcUrl = getCurrentRpcUrl();
  const response = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_sendRawTransaction',
      params: [signedTx],
      id: 1,
    }),
  });

  const data = await response.json();
  if (data.error) {
    throw new Error(`广播交易失败: ${data.error.message}`);
  }
  return data.result; // 返回交易哈希
}

/**
 * 获取交易收据 (确认状态)
 */
export async function getTransactionReceipt(txHash: string): Promise<unknown | null> {
  const rpcUrl = getCurrentRpcUrl();
  const response = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'eth_getTransactionReceipt',
      params: [txHash],
      id: 1,
    }),
  });

  const data = await response.json();
  return data.result;
}

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

/**
 * 验证金额格式
 */
export function isValidAmount(amount: string): boolean {
  if (!amount || amount.trim() === '') return false;
  const num = parseFloat(amount);
  return !isNaN(num) && num > 0;
}
