/**
 * <rpast-viewer> — Chronicle-of-self timeline, rendered as a canvas shape.
 *
 * Hits the server-rendered `/:space/rpast/render` endpoint via iframe for
 * the actual timeline/calendar visualization. The chip bar drives query
 * params; the iframe reloads on every change.
 *
 * Attribute: space — the space slug
 */

import '../../../shared/components/rstack-markwhen-view';

type ViewMode = 'timeline' | 'calendar';

interface ModuleInfo { module: string; label: string; icon: string; color?: string; }

export class RpastViewer extends HTMLElement {
	static get observedAttributes() { return ['space']; }

	#space = '';
	#selected: Set<string> | null = null; // null = "all"
	#mode: ViewMode = 'timeline';
	#modules: ModuleInfo[] = [];
	#shadow: ShadowRoot;

	constructor() {
		super();
		this.#shadow = this.attachShadow({ mode: 'open' });
		this.#shadow.innerHTML = `
			<style>
				:host { display: grid; grid-template-rows: auto 1fr auto; height: 100%; width: 100%; }
				.bar { display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
					padding: 6px 10px; background: #0f172a; border-bottom: 1px solid #1e293b;
					font: 12px system-ui; color: #cbd5e1; }
				.chip { padding: 2px 10px; border-radius: 999px; background: #1e293b;
					cursor: pointer; user-select: none; white-space: nowrap; }
				.chip[aria-pressed="true"] { background: #2563eb; color: white; }
				.spacer { flex: 1; }
				.toggle { display: flex; gap: 4px; }
				.toggle button { border: 0; background: #1e293b; color: #cbd5e1; padding: 2px 10px;
					border-radius: 4px; font: 12px system-ui; cursor: pointer; }
				.toggle button[aria-pressed="true"] { background: #2563eb; color: white; }
				.foot { display: flex; gap: 16px; padding: 4px 10px; font: 11px system-ui;
					color: #94a3b8; background: #0f172a; border-top: 1px solid #1e293b; }
				.foot a { color: #60a5fa; text-decoration: none; }
				.foot a:hover { text-decoration: underline; }
			</style>
			<div class="bar"></div>
			<rstack-markwhen-view></rstack-markwhen-view>
			<div class="foot"><span class="count">Loading…</span><span class="spacer"></span><a class="download" href="#">Download .mw</a></div>
		`;
	}

	set space(v: string) { this.#space = v; void this.#init(); }
	get space() { return this.#space; }

	attributeChangedCallback(name: string, _old: string | null, next: string | null) {
		if (name === 'space') this.space = next ?? '';
	}

	connectedCallback() { void this.#init(); }

	async #init() {
		if (!this.#space) return;
		try {
			// The modules endpoint is space-agnostic; any space path works.
			const res = await fetch(`/${this.#space}/rpast/api/modules`);
			this.#modules = await res.json();
		} catch (err) {
			console.error('[rpast-viewer] failed to load module list', err);
			this.#modules = [];
		}
		this.#paintBar();
		await this.#reload();
	}

	#paintBar() {
		const bar = this.#shadow.querySelector('.bar')!;
		bar.innerHTML = '';

		const allChip = document.createElement('span');
		allChip.className = 'chip';
		allChip.setAttribute('aria-pressed', String(this.#selected === null));
		allChip.textContent = '✨ All';
		allChip.addEventListener('click', () => { this.#selected = null; this.#paintBar(); void this.#reload(); });
		bar.appendChild(allChip);

		for (const m of this.#modules) {
			const chip = document.createElement('span');
			chip.className = 'chip';
			const active = this.#selected !== null && this.#selected.has(m.module);
			chip.setAttribute('aria-pressed', String(active));
			chip.textContent = `${m.icon} ${m.label}`;
			chip.addEventListener('click', () => this.#toggle(m.module));
			bar.appendChild(chip);
		}

		const spacer = document.createElement('div');
		spacer.className = 'spacer';
		bar.appendChild(spacer);

		const toggle = document.createElement('div');
		toggle.className = 'toggle';
		for (const mode of ['timeline', 'calendar'] as const) {
			const btn = document.createElement('button');
			btn.textContent = mode[0].toUpperCase() + mode.slice(1);
			btn.setAttribute('aria-pressed', String(this.#mode === mode));
			btn.addEventListener('click', () => { this.#mode = mode; this.#paintBar(); void this.#reload(); });
			toggle.appendChild(btn);
		}
		bar.appendChild(toggle);
	}

	#toggle(module: string) {
		if (this.#selected === null) this.#selected = new Set([module]);
		else if (this.#selected.has(module)) {
			this.#selected.delete(module);
			if (this.#selected.size === 0) this.#selected = null;
		} else this.#selected.add(module);
		this.#paintBar();
		void this.#reload();
	}

	#buildUrl(base: string): string {
		const params = new URLSearchParams();
		if (this.#selected) params.set('modules', [...this.#selected].join(','));
		params.set('view', this.#mode);
		return `/${this.#space}/rpast/${base}?${params.toString()}`;
	}

	async #reload() {
		const view = this.#shadow.querySelector('rstack-markwhen-view') as HTMLElement & {
			src?: string; view?: ViewMode;
		};
		view.view = this.#mode;
		view.src = this.#buildUrl('render');

		const dl = this.#shadow.querySelector('.download') as HTMLAnchorElement;
		dl.href = this.#buildUrl('api/chronicle.mw');
		dl.download = `${this.#space}-rpast.mw`;

		try {
			const res = await fetch(this.#buildUrl('api/chronicle'));
			const data = await res.json() as { count: number; sections: { id: string; count: number }[] };
			const foot = this.#shadow.querySelector('.count') as HTMLElement;
			foot.textContent = `${data.count.toLocaleString()} creation${data.count === 1 ? '' : 's'} across ${data.sections.length} module${data.sections.length === 1 ? '' : 's'}`;
		} catch (err) {
			console.error('[rpast-viewer] count fetch failed', err);
		}
	}
}

if (!customElements.get('rpast-viewer')) {
	customElements.define('rpast-viewer', RpastViewer);
}
