#!/usr/bin/env bun
/**
 * Full-loop integration test: fiat in → cUSDC → $MYCO → cUSDC → fiat out.
 *
 * Tests all 5 phases of the HyperSwitch payment orchestrator integration.
 * Run against a local dev instance with: bun scripts/test-full-loop.ts
 *
 * Expects:
 *   - rspace-online running at BASE_URL (default: http://localhost:3000)
 *   - payment-infra services running (or mock responses)
 *   - INTERNAL_API_KEY set for internal endpoints
 */

const BASE_URL = process.env.BASE_URL || "http://localhost:3000";
const INTERNAL_KEY = process.env.INTERNAL_API_KEY || "test-internal-key";
const TEST_DID = process.env.TEST_DID || "did:key:test-full-loop-2026";
const TEST_LABEL = "test-user";

type StepResult = { ok: boolean; data?: any; error?: string };

async function step(name: string, fn: () => Promise<StepResult>) {
	process.stdout.write(`  ${name}... `);
	try {
		const result = await fn();
		if (result.ok) {
			console.log("OK", result.data ? JSON.stringify(result.data).slice(0, 120) : "");
		} else {
			console.log("FAIL", result.error || JSON.stringify(result.data));
		}
		return result;
	} catch (err: any) {
		console.log("ERROR", err.message);
		return { ok: false, error: err.message } as StepResult;
	}
}

async function main() {
	console.log("\n=== HyperSwitch Full Loop Test ===\n");
	console.log(`Base URL: ${BASE_URL}`);
	console.log(`Test DID: ${TEST_DID}\n`);

	// ── Phase 1: Health check ──
	console.log("Phase 1: Infrastructure");
	await step("rspace-online health", async () => {
		const resp = await fetch(`${BASE_URL}/api/communities`);
		return { ok: resp.ok, data: { status: resp.status } };
	});

	// ── Phase 2: Fiat on-ramp (simulate mint-crdt call) ──
	console.log("\nPhase 2: Fiat On-Ramp (cUSDC mint)");

	const mintResult = await step("POST /api/internal/mint-crdt", async () => {
		const resp = await fetch(`${BASE_URL}/api/internal/mint-crdt`, {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				"X-Internal-Key": INTERNAL_KEY,
			},
			body: JSON.stringify({
				did: TEST_DID,
				label: TEST_LABEL,
				amountDecimal: "100.000000",
				txHash: `hs-test-${Date.now()}`,
				network: "hyperswitch:fiat:usd",
			}),
		});
		const data = await resp.json();
		return { ok: resp.ok && data.ok, data };
	});

	await step("Idempotency check (same txHash)", async () => {
		const resp = await fetch(`${BASE_URL}/api/internal/mint-crdt`, {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				"X-Internal-Key": INTERNAL_KEY,
			},
			body: JSON.stringify({
				did: TEST_DID,
				label: TEST_LABEL,
				amountDecimal: "100.000000",
				txHash: mintResult.data?.txHash || `hs-test-idempotent`,
				network: "hyperswitch:fiat:usd",
			}),
		});
		const data = await resp.json();
		// Should return ok:false because already minted
		return { ok: resp.ok && !data.ok, data };
	});

	// ── Phase 3: $MYCO bonding curve ──
	console.log("\nPhase 3: $MYCO Bonding Curve");

	await step("GET /api/crdt-tokens/myco/quote?action=buy&amount=10", async () => {
		const resp = await fetch(`${BASE_URL}/demo/rwallet/api/crdt-tokens/myco/quote?action=buy&amount=10`);
		const data = await resp.json();
		return {
			ok: resp.ok && data.output?.amount > 0,
			data: { output: data.output?.amount, price: data.pricePerToken, impact: data.priceImpact },
		};
	});

	await step("GET /api/crdt-tokens/myco/quote?action=sell&amount=100", async () => {
		const resp = await fetch(`${BASE_URL}/demo/rwallet/api/crdt-tokens/myco/quote?action=sell&amount=100`);
		const data = await resp.json();
		return {
			ok: resp.ok && data.output?.amount > 0,
			data: { output: data.output?.amount, fee: data.fee?.amount, impact: data.priceImpact },
		};
	});

	await step("GET /api/crdt-tokens/myco/settlement-state", async () => {
		const resp = await fetch(`${BASE_URL}/demo/rwallet/api/crdt-tokens/myco/settlement-state`);
		const data = await resp.json();
		return {
			ok: resp.ok && data.mycoSupply >= 0,
			data: { supply: data.mycoSupply, price: data.currentPrice, reserve: data.reserveBalance },
		};
	});

	// ── Phase 4: Off-ramp (simulate escrow + confirm) ──
	console.log("\nPhase 4: Fiat Off-Ramp (escrow burn)");

	const offRampId = `offramp-test-${Date.now()}`;
	await step("POST /api/internal/escrow-burn", async () => {
		const resp = await fetch(`${BASE_URL}/api/internal/escrow-burn`, {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				"X-Internal-Key": INTERNAL_KEY,
			},
			body: JSON.stringify({
				did: TEST_DID,
				label: TEST_LABEL,
				amount: 10_000_000, // 10 cUSDC
				offRampId,
			}),
		});
		const data = await resp.json();
		return { ok: resp.ok && data.ok, data };
	});

	await step("POST /api/internal/confirm-offramp (confirmed)", async () => {
		const resp = await fetch(`${BASE_URL}/api/internal/confirm-offramp`, {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				"X-Internal-Key": INTERNAL_KEY,
			},
			body: JSON.stringify({ offRampId, status: "confirmed" }),
		});
		const data = await resp.json();
		return { ok: resp.ok && data.ok, data };
	});

	// Test reversal flow
	const offRampId2 = `offramp-test-reverse-${Date.now()}`;
	await step("Escrow + reverse flow", async () => {
		// Escrow
		const escrowResp = await fetch(`${BASE_URL}/api/internal/escrow-burn`, {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				"X-Internal-Key": INTERNAL_KEY,
			},
			body: JSON.stringify({
				did: TEST_DID,
				label: TEST_LABEL,
				amount: 5_000_000, // 5 cUSDC
				offRampId: offRampId2,
			}),
		});
		if (!escrowResp.ok) return { ok: false, error: "escrow failed" };

		// Reverse
		const reverseResp = await fetch(`${BASE_URL}/api/internal/confirm-offramp`, {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				"X-Internal-Key": INTERNAL_KEY,
			},
			body: JSON.stringify({ offRampId: offRampId2, status: "reversed" }),
		});
		const data = await reverseResp.json();
		return { ok: reverseResp.ok && data.ok, data: { action: "reversed", refunded: "5 cUSDC" } };
	});

	// ── Phase 5: CRDT token list ──
	console.log("\nPhase 5: Token Verification");

	await step("GET /api/crdt-tokens (list all tokens)", async () => {
		const resp = await fetch(`${BASE_URL}/demo/rwallet/api/crdt-tokens`);
		const data = await resp.json();
		const symbols = (data.tokens || []).map((t: any) => t.symbol);
		return {
			ok: resp.ok && symbols.includes("cUSDC") && symbols.includes("$MYCO"),
			data: { tokens: symbols },
		};
	});

	console.log("\n=== Full Loop Test Complete ===\n");
}

main().catch(console.error);
