/**
 * End-to-end test for Solana x402 payment integration.
 *
 * Validates that ClawRouter correctly:
 *   1. Derives both EVM and Solana wallets from a BIP-39 mnemonic
 *   2. Registers both EVM and Solana x402 schemes
 *   3. Connects to the real BlockRun API
 *   4. Handles the 402 payment flow (payment attempt, even if wallet is unfunded)
 *
 * Usage:
 *   npx tsx test/test-solana-e2e.ts
 *
 * With a funded wallet (full E2E):
 *   BLOCKRUN_WALLET_KEY=0x... npx tsx test/test-solana-e2e.ts
 */

import { startProxy } from "../src/proxy.js";
import { generateWalletMnemonic, deriveEvmKey, deriveSolanaKeyBytes } from "../src/wallet.js";

let passed = 0;
let failed = 0;

function assert(condition: boolean, msg: string) {
  if (condition) {
    console.log(`  ✓ ${msg}`);
    passed++;
  } else {
    console.error(`  ✗ FAIL: ${msg}`);
    failed++;
  }
}

async function run() {
  console.log("\n═══ Solana E2E Integration Test ═══\n");

  // --- Part 1: Wallet Derivation ---
  console.log("--- Part 1: Wallet derivation from mnemonic ---\n");

  const mnemonic = generateWalletMnemonic();
  assert(mnemonic.split(" ").length === 24, "Generated 24-word mnemonic");

  const evm = deriveEvmKey(mnemonic);
  assert(
    evm.privateKey.startsWith("0x") && evm.privateKey.length === 66,
    `EVM key derived: ${evm.privateKey.slice(0, 10)}...`,
  );

  const solanaBytes = deriveSolanaKeyBytes(mnemonic);
  assert(solanaBytes.length === 32, `Solana private key derived: ${solanaBytes.length} bytes`);

  // Verify Solana signer creation
  const { createKeyPairSignerFromPrivateKeyBytes } = await import("@solana/kit");
  const solanaSigner = await createKeyPairSignerFromPrivateKeyBytes(solanaBytes);
  assert(
    typeof solanaSigner.address === "string" && solanaSigner.address.length > 30,
    `Solana address: ${solanaSigner.address}`,
  );

  // --- Part 2: Proxy with dual-chain support ---
  console.log("\n--- Part 2: Proxy startup with both chains ---\n");

  // Use env wallet if available, otherwise use the generated one
  const walletKey = process.env.BLOCKRUN_WALLET_KEY ?? evm.privateKey;
  const solanaKeyBytes = process.env.BLOCKRUN_WALLET_KEY ? undefined : solanaBytes;
  const requestedChain = solanaKeyBytes ? "solana" : "base";

  const proxy = await startProxy({
    wallet: { key: walletKey, solanaPrivateKeyBytes: solanaKeyBytes },
    paymentChain: requestedChain,
    port: 0,
    skipBalanceCheck: true,
    onReady: (port) => console.log(`  Proxy started on port ${port}`),
  });

  assert(proxy.port > 0, `Proxy listening on port ${proxy.port}`);
  assert(typeof proxy.walletAddress === "string", `EVM wallet: ${proxy.walletAddress}`);

  // --- Part 3: Health check ---
  console.log("\n--- Part 3: Health endpoint ---\n");

  const healthRes = await fetch(`http://127.0.0.1:${proxy.port}/health`);
  const healthData = (await healthRes.json()) as {
    status: string;
    wallet: string;
    solana?: string;
    paymentChain?: "base" | "solana";
  };
  assert(healthData.status === "ok", `Health status: ${healthData.status}`);
  assert(typeof healthData.wallet === "string", `Health reports EVM wallet: ${healthData.wallet}`);
  assert(
    healthData.paymentChain === requestedChain,
    `Health reports payment chain: ${healthData.paymentChain}`,
  );
  if (requestedChain === "solana") {
    assert(
      typeof healthData.solana === "string" && healthData.solana.length > 30,
      `Health reports Solana wallet: ${healthData.solana}`,
    );
  }

  // --- Part 4: Real API request (402 payment flow) ---
  console.log("\n--- Part 4: BlockRun API request (402 flow) ---\n");

  try {
    const res = await fetch(`http://127.0.0.1:${proxy.port}/v1/chat/completions`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        model: "deepseek/deepseek-chat",
        messages: [{ role: "user", content: "Say hello" }],
        max_tokens: 10,
      }),
      signal: AbortSignal.timeout(30_000),
    });

    if (res.ok) {
      // Wallet was funded - full E2E success
      const text = await res.text();
      assert(true, `Request succeeded (funded wallet): status ${res.status}`);
      assert(text.length > 0, `Response body received: ${text.length} chars`);
    } else {
      // 402 flow was attempted but payment failed (expected for unfunded wallet)
      const body = await res.text();
      const isPaymentError =
        body.includes("insufficient") ||
        body.includes("balance") ||
        body.includes("payment") ||
        body.includes("402") ||
        body.includes("fund") ||
        res.status === 402;

      assert(
        isPaymentError || res.status === 500,
        `Payment flow reached (status ${res.status}): ${body.slice(0, 200)}`,
      );
    }
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    // Connection errors mean the proxy or API is unreachable - that's a real failure
    // Payment/timeout errors mean the 402 flow was attempted - that's success
    const isExpected = msg.includes("timeout") || msg.includes("abort");
    assert(isExpected, `Request outcome: ${msg.slice(0, 200)}`);
  }

  // --- Part 5: Models endpoint ---
  console.log("\n--- Part 5: Models endpoint reachable ---\n");

  try {
    const modelsRes = await fetch(`http://127.0.0.1:${proxy.port}/v1/models`, {
      signal: AbortSignal.timeout(10_000),
    });
    assert(modelsRes.ok, `Models endpoint: status ${modelsRes.status}`);
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    assert(false, `Models endpoint failed: ${msg}`);
  }

  // Cleanup
  await proxy.close();
  console.log("\n  Proxy closed.");

  // Summary
  console.log("\n═══════════════════════════════════");
  console.log(`  ${passed} passed, ${failed} failed`);
  console.log("═══════════════════════════════════\n");

  process.exit(failed > 0 ? 1 : 0);
}

run().catch((err) => {
  console.error("Fatal:", err);
  process.exit(1);
});
