/**
 * Funds module — budget flows, river visualization, and treasury management.
 *
 * Proxies flow-service API calls and serves the BudgetRiver visualization.
 */

import { Hono } from "hono";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { sql } from "../../shared/db/pool";
import { renderShell } from "../../server/shell";
import type { RSpaceModule } from "../../shared/module";
import { getModuleInfoList } from "../../shared/module";
import { verifyEncryptIDToken, extractToken } from "@encryptid/sdk/server";
import { renderLanding } from "./landing";

const FLOW_SERVICE_URL = process.env.FLOW_SERVICE_URL || "http://payment-flow:3010";

// ── DB initialization ──
const SCHEMA_SQL = readFileSync(resolve(import.meta.dir, "db/schema.sql"), "utf-8");

async function initDB() {
	try {
		await sql.unsafe(SCHEMA_SQL);
		console.log("[Funds] DB schema initialized");
	} catch (e) {
		console.error("[Funds] DB init error:", e);
	}
}

initDB();

const routes = new Hono();

// ─── Flow Service API proxy ─────────────────────────────
// These proxy to the payment-flow backend so the frontend
// can call them from the same origin.

routes.get("/api/flows", async (c) => {
	const owner = c.req.header("X-Owner-Address") || "";
	const space = c.req.query("space") || "";

	// If space filter provided, get flow IDs from space_flows table
	if (space) {
		try {
			const rows = await sql.unsafe(
				"SELECT flow_id FROM rfunds.space_flows WHERE space_slug = $1",
				[space],
			);
			if (rows.length === 0) return c.json([]);

			// Fetch each flow from flow-service
			const flows = await Promise.all(
				rows.map(async (r: any) => {
					try {
						const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${r.flow_id}`);
						if (res.ok) return await res.json();
					} catch {}
					return null;
				}),
			);
			return c.json(flows.filter(Boolean));
		} catch {
			// Fall through to unfiltered fetch
		}
	}

	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows?owner=${encodeURIComponent(owner)}`);
	return c.json(await res.json(), res.status as any);
});

routes.get("/api/flows/:flowId", async (c) => {
	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}`);
	return c.json(await res.json(), res.status as any);
});

routes.post("/api/flows", async (c) => {
	// Auth-gated: require EncryptID token
	const token = extractToken(c.req.raw.headers);
	if (!token) return c.json({ error: "Authentication required" }, 401);

	let claims;
	try { claims = await verifyEncryptIDToken(token); } catch { return c.json({ error: "Invalid token" }, 401); }

	const body = await c.req.text();
	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows`, {
		method: "POST",
		headers: {
			"Content-Type": "application/json",
			"X-Owner-Address": claims.sub,
		},
		body,
	});
	return c.json(await res.json(), res.status as any);
});

routes.post("/api/flows/:flowId/deposit", async (c) => {
	const body = await c.req.text();
	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/deposit`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body,
	});
	return c.json(await res.json(), res.status as any);
});

routes.post("/api/flows/:flowId/withdraw", async (c) => {
	const body = await c.req.text();
	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/withdraw`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body,
	});
	return c.json(await res.json(), res.status as any);
});

routes.post("/api/flows/:flowId/activate", async (c) => {
	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/activate`, { method: "POST" });
	return c.json(await res.json(), res.status as any);
});

routes.post("/api/flows/:flowId/pause", async (c) => {
	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/pause`, { method: "POST" });
	return c.json(await res.json(), res.status as any);
});

routes.post("/api/flows/:flowId/funnels", async (c) => {
	const body = await c.req.text();
	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/funnels`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body,
	});
	return c.json(await res.json(), res.status as any);
});

routes.post("/api/flows/:flowId/outcomes", async (c) => {
	const body = await c.req.text();
	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/outcomes`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body,
	});
	return c.json(await res.json(), res.status as any);
});

routes.get("/api/flows/:flowId/transactions", async (c) => {
	const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/transactions`);
	return c.json(await res.json(), res.status as any);
});

// ─── Space-flow association endpoints ────────────────────

routes.post("/api/space-flows", async (c) => {
	const token = extractToken(c.req.raw.headers);
	if (!token) return c.json({ error: "Authentication required" }, 401);

	let claims;
	try { claims = await verifyEncryptIDToken(token); } catch { return c.json({ error: "Invalid token" }, 401); }

	const { space, flowId } = await c.req.json();
	if (!space || !flowId) return c.json({ error: "space and flowId required" }, 400);

	await sql.unsafe(
		`INSERT INTO rfunds.space_flows (space_slug, flow_id, added_by)
		 VALUES ($1, $2, $3) ON CONFLICT DO NOTHING`,
		[space, flowId, claims.sub],
	);
	return c.json({ ok: true });
});

routes.delete("/api/space-flows/:flowId", async (c) => {
	const token = extractToken(c.req.raw.headers);
	if (!token) return c.json({ error: "Authentication required" }, 401);

	try { await verifyEncryptIDToken(token); } catch { return c.json({ error: "Invalid token" }, 401); }

	const flowId = c.req.param("flowId");
	const space = c.req.query("space") || "";
	if (!space) return c.json({ error: "space query param required" }, 400);

	await sql.unsafe(
		"DELETE FROM rfunds.space_flows WHERE space_slug = $1 AND flow_id = $2",
		[space, flowId],
	);
	return c.json({ ok: true });
});

// ─── Page routes ────────────────────────────────────────

const fundsScripts = `
	<script src="https://cdn.jsdelivr.net/npm/lz-string@1.5.0/libs/lz-string.min.js"></script>
	<script type="module" src="/modules/rfunds/folk-funds-app.js"></script>
	<script type="module" src="/modules/rfunds/folk-budget-river.js"></script>`;

const fundsStyles = `<link rel="stylesheet" href="/modules/rfunds/funds.css">`;

// Landing page
routes.get("/", (c) => {
	const spaceSlug = c.req.param("space") || "demo";
	return c.html(renderShell({
		title: `${spaceSlug} — Funds | rSpace`,
		moduleId: "rfunds",
		spaceSlug,
		modules: getModuleInfoList(),
		theme: "dark",
		body: `<folk-funds-app space="${spaceSlug}"></folk-funds-app>`,
		scripts: `<script type="module" src="/modules/rfunds/folk-funds-app.js"></script>`,
		styles: `<link rel="stylesheet" href="/modules/rfunds/funds.css">`,
	}));
});

// Demo mode — hardcoded demo data, no API needed
routes.get("/demo", (c) => {
	const spaceSlug = c.req.param("space") || "demo";
	return c.html(renderShell({
		title: `TBFF Demo — rFunds | rSpace`,
		moduleId: "rfunds",
		spaceSlug,
		modules: getModuleInfoList(),
		theme: "dark",
		styles: fundsStyles,
		body: `<folk-funds-app space="${spaceSlug}" mode="demo"></folk-funds-app>`,
		scripts: fundsScripts,
	}));
});

// Flow detail — specific flow from API
routes.get("/flow/:flowId", (c) => {
	const spaceSlug = c.req.param("space") || "demo";
	const flowId = c.req.param("flowId");
	return c.html(renderShell({
		title: `Flow — rFunds | rSpace`,
		moduleId: "rfunds",
		spaceSlug,
		modules: getModuleInfoList(),
		theme: "dark",
		styles: fundsStyles,
		body: `<folk-funds-app space="${spaceSlug}" flow-id="${flowId}"></folk-funds-app>`,
		scripts: fundsScripts,
	}));
});

export const fundsModule: RSpaceModule = {
	id: "rfunds",
	name: "rFunds",
	icon: "🌊",
	description: "Budget flows, river visualization, and treasury management",
	scoping: { defaultScope: 'space', userConfigurable: false },
	routes,
	landingPage: renderLanding,
	standaloneDomain: "rfunds.online",
	feeds: [
		{
			id: "treasury-flows",
			name: "Treasury Flows",
			kind: "economic",
			description: "Budget flow states, deposits, withdrawals, and funnel allocations",
			filterable: true,
		},
		{
			id: "transactions",
			name: "Transaction Stream",
			kind: "economic",
			description: "Real-time deposit and withdrawal events",
		},
	],
	acceptsFeeds: ["governance", "data"],
	outputPaths: [
		{ path: "budgets", name: "Budgets", icon: "💰", description: "Budget allocations and funnels" },
		{ path: "flows", name: "Flows", icon: "🌊", description: "Revenue and resource flow visualizations" },
	],
};
