/**
 * Landing page proxy.
 *
 * Fetches pre-rendered HTML from standalone r*.online domains, transforms it
 * with Bun's HTMLRewriter (rewrite asset URLs, strip scripts, inject rSpace
 * shell header), caches the result, and serves it on rspace.online/{moduleId}.
 *
 * Falls back to the generic landing page if the fetch fails.
 */

import type { ModuleInfo } from "../shared/module";
import { escapeHtml, escapeAttr } from "./shell";

// ── Cache ──

interface CacheEntry {
	html: string;
	fetchedAt: number;
}

const cache = new Map<string, CacheEntry>();
const CACHE_TTL = 10 * 60 * 1000; // 10 minutes

// ── Ecosystem link rewriting ──

/** Map standalone domains → rspace.online paths for footer links */
function buildEcosystemMap(modules: ModuleInfo[]): Map<string, string> {
	const map = new Map<string, string>();
	for (const m of modules) {
		if (m.standaloneDomain) {
			map.set(`https://${m.standaloneDomain}`, `https://rspace.online/${m.id}`);
			// Also catch without trailing slash
			map.set(`https://www.${m.standaloneDomain}`, `https://rspace.online/${m.id}`);
		}
	}
	return map;
}

// ── Shell header HTML ──

function renderShellHeader(moduleId: string, modules: ModuleInfo[]): string {
	const moduleListJSON = JSON.stringify(modules);
	const demoUrl = `https://demo.rspace.online/${escapeAttr(moduleId)}`;

	return `<header class="rstack-header" data-theme="dark">
  <div class="rstack-header__left">
    <rstack-app-switcher current="${escapeAttr(moduleId)}"></rstack-app-switcher>
  </div>
  <div class="rstack-header__center"></div>
  <div class="rstack-header__right">
    <a class="rstack-header__demo-btn" href="${demoUrl}">Try Demo</a>
    <rstack-identity></rstack-identity>
  </div>
</header>
<script type="module">
  import '/shell.js';
  document.querySelector('rstack-app-switcher')?.setModules(${moduleListJSON});
  // Logged-in users: hide header demo btn
  try {
    var raw = localStorage.getItem('encryptid_session');
    if (raw) {
      var btn = document.querySelector('.rstack-header__demo-btn');
      if (btn) btn.setAttribute('data-hide', '');
    }
  } catch(e) {}
</script>`;
}

// ── Main export ──

export async function fetchLandingPage(
	mod: { id: string; standaloneDomain?: string },
	modules: ModuleInfo[],
): Promise<string | null> {
	const domain = mod.standaloneDomain;
	if (!domain) return null;

	const now = Date.now();
	const cached = cache.get(domain);

	// Return fresh cache
	if (cached && now - cached.fetchedAt < CACHE_TTL) {
		return cached.html;
	}

	try {
		const controller = new AbortController();
		const timeout = setTimeout(() => controller.abort(), 5000);

		const res = await fetch(`https://${domain}`, {
			headers: { "User-Agent": "rSpace-Proxy/1.0" },
			signal: controller.signal,
		});
		clearTimeout(timeout);

		if (!res.ok) {
			// Return stale cache if available
			if (cached) return cached.html;
			return null;
		}

		const rawHtml = await res.text();

		// Transform with HTMLRewriter
		const html = await transformWithRewriter(rawHtml, domain, mod.id, modules);

		cache.set(domain, { html, fetchedAt: now });
		return html;
	} catch (e) {
		// Network error / timeout — return stale cache if available
		if (cached) return cached.html;
		console.error(`[LandingProxy] Failed to fetch ${domain}:`, (e as Error).message);
		return null;
	}
}

/** Async HTMLRewriter transform (Bun's HTMLRewriter works on Response objects) */
async function transformWithRewriter(
	rawHtml: string,
	domain: string,
	moduleId: string,
	modules: ModuleInfo[],
): Promise<string> {
	const ecosystemMap = buildEcosystemMap(modules);
	const origin = `https://${domain}`;
	let headerInjected = false;

	const rewriter = new HTMLRewriter();

	// 1. Rewrite _next asset URLs to absolute (CSS, fonts, images)
	rewriter.on('link[href^="/_next/"]', {
		element(el) {
			const href = el.getAttribute("href");
			if (href) el.setAttribute("href", `${origin}${href}`);
		},
	});
	rewriter.on('img[src^="/_next/"]', {
		element(el) {
			const src = el.getAttribute("src");
			if (src) el.setAttribute("src", `${origin}${src}`);
		},
	});

	// 2. Strip all <script> tags
	rewriter.on("script", {
		element(el) {
			el.remove();
		},
	});

	// 3. Replace first <nav> with rSpace shell header
	rewriter.on("nav", {
		element(el) {
			if (!headerInjected) {
				headerInjected = true;
				el.replace(renderShellHeader(moduleId, modules), { html: true });
			}
		},
	});

	// 4. Inject shell.css + analytics into <head>
	rewriter.on("head", {
		element(el) {
			el.append(
				`<link rel="stylesheet" href="/shell.css">
<script defer src="/collect.js" data-website-id="6ee7917b-0ed7-44cb-a4c8-91037638526b"></script>`,
				{ html: true },
			);
		},
	});

	// 5. If no <nav> was found, prepend shell header to <body>
	rewriter.on("body", {
		element(el) {
			if (!headerInjected) {
				headerInjected = true;
				el.prepend(renderShellHeader(moduleId, modules), { html: true });
			}
		},
	});

	// 6. Rewrite ecosystem links (standalone domain URLs → rspace.online paths)
	rewriter.on("a[href]", {
		element(el) {
			const href = el.getAttribute("href");
			if (href) {
				for (const [standaloneUrl, rspaceUrl] of ecosystemMap) {
					if (href === standaloneUrl || href === standaloneUrl + "/") {
						el.setAttribute("href", rspaceUrl);
						break;
					}
				}
			}
		},
	});

	const transformed = rewriter.transform(new Response(rawHtml));
	return transformed.text();
}
