/**
 * rPast — chronicle-of-self timeline.
 *
 * Projects every dated CRDT record across every rApp into a single
 * timeline/calendar. Zero writes to source modules. The `.mw` text is
 * regenerated on every request; saved "chronicles" are just filter configs.
 */

import { Hono } from 'hono';
import type { RSpaceModule } from '../../shared/module';
import {
	enumerateCreations, listCreationEnumerators, renderMarkwhen,
} from '../../shared/markwhen';
import { renderMarkwhenHtml } from '../../shared/markwhen/html-render';
import { renderShell } from '../../server/shell';
import { getModuleInfoList } from '../../shared/module';
import { pastSchema } from './schemas';
import { renderLanding } from './landing';

const routes = new Hono();

// GET / — marketing landing on bare domain, interactive viewer in a space.
routes.get('/', c => {
	const space = c.req.param('space') || 'demo';
	if (!space || space === 'rpast.online') {
		return c.html(renderLanding());
	}
	return c.html(renderShell({
		title: `${space} — rPast | rSpace`,
		moduleId: 'rpast',
		spaceSlug: space,
		modules: getModuleInfoList(),
		theme: 'dark',
		body: `<rpast-viewer space="${space}" style="height:calc(100vh - 52px);display:block"></rpast-viewer>`,
		scripts: `<script type="module" src="/modules/rpast/rpast-viewer.js?v=1"></script>`,
	}));
});

routes.get('/api/modules', c => {
	return c.json(listCreationEnumerators().map(e => ({
		module: e.module, label: e.label, icon: e.icon, color: e.color,
	})));
});

async function buildProjection(c: any) {
	const space = c.req.param('space');
	const modules = c.req.query('modules')?.split(',').filter(Boolean);
	const from = c.req.query('from') ? Number(c.req.query('from')) : undefined;
	const to = c.req.query('to') ? Number(c.req.query('to')) : undefined;
	const view = (c.req.query('view') as 'timeline' | 'calendar') ?? 'timeline';

	// Derive the public base URL from the request so in-timeline "Open in
	// rApp" links resolve against the same origin the user arrived from.
	// rSpace production is always behind Cloudflare/Traefik TLS, so for any
	// non-loopback host we always emit https — forwarded-proto headers can
	// be `http` (internal Traefik→container hop) even though the real client
	// request was https.
	const host = c.req.header('x-forwarded-host') ?? c.req.header('host');
	const isLocal = !host || /^(localhost|127\.|\[::1\])/i.test(host);
	const proto = isLocal ? 'http' : 'https';
	const baseUrl = host ? `${proto}://${host}` : undefined;

	const sources = await enumerateCreations(space, { modules, from, to });
	const projection = renderMarkwhen(sources, {
		view, title: `${space} — rPast`, baseUrl,
	});
	return { space, sources, projection, view };
}

routes.get('/api/chronicle', async c => {
	const { sources, projection } = await buildProjection(c);
	return c.json({
		text: projection.text,
		count: projection.count,
		sections: sources.map(s => ({ id: s.id, label: s.label, count: s.events.length })),
	});
});

routes.get('/api/chronicle.mw', async c => {
	const { projection } = await buildProjection(c);
	return c.text(projection.text, 200, { 'content-type': 'text/plain; charset=utf-8' });
});

routes.get('/render', async c => {
	const { projection, view } = await buildProjection(c);
	const html = renderMarkwhenHtml(projection.text, view);
	return c.html(html);
});

export const rpastModule: RSpaceModule = {
	id: 'rpast',
	name: 'rPast',
	icon: '🕰️',
	description: 'Chronicle-of-self — every rApp creation, ever, on one timeline.',
	routes,
	landingPage: renderLanding,
	scoping: { defaultScope: 'space', userConfigurable: false },
	docSchemas: [{
		pattern: '{space}:rpast:chronicles',
		description: 'Saved chronicle configs (module selection + filters + mode)',
		init: pastSchema.init,
	}],
};
