/**
 * Universal declarative creation enumerator.
 *
 * Rather than write a bespoke enumerator per rApp, each module declares a
 * `CreationSpec` that names its Automerge doc patterns, the collection keys
 * holding records, and a few per-collection accessors. One generic engine
 * walks the docs and emits creations for all modules uniformly.
 *
 * Adding a new module to rPast = ~10 lines in `creation-specs.ts`.
 */

import { loadDoc, listDocIds } from './doc-loader';
import type { Creation, CreationEnumerator } from './creations';

export interface CreationCollection {
	/** Top-level key in the doc (e.g. "events", "tasks", "notes"). */
	path: string;
	/** Short record-type tag, e.g. "event", "task", "note". */
	recordType: string;
	/** Field on the record holding the creation timestamp. Defaults to "createdAt". */
	timestampField?: string;
	/** Pick the display title. Default: record.title || record.name || record.path || id. */
	title?: (record: Record<string, unknown>, id: string) => string;
	/** Build a deep-link URL for a record. */
	href?: (args: { space: string; docId: string; id: string; record: Record<string, unknown> }) => string | undefined;
	/** Emit extra per-record tags. */
	tags?: (record: Record<string, unknown>) => string[] | undefined;
	/** Return false to skip a record (e.g. abstain votes, tombstones). */
	filter?: (record: Record<string, unknown>) => boolean;
	/** Pull a short description body. */
	description?: (record: Record<string, unknown>) => string | undefined;
}

export interface CreationSpec {
	module: string;
	label: string;
	icon: string;
	color?: string;
	/**
	 * Doc-ID patterns this module owns.
	 *   `{space}` is replaced with the space slug.
	 *   Trailing `*` is a prefix wildcard (expanded via listDocIds).
	 *   Otherwise the pattern is loaded as a single doc.
	 * Examples:
	 *   `{space}:cal:events`                (single doc)
	 *   `{space}:rnotes:vaults:*`           (fan-out over all vaults)
	 */
	docPatterns: string[];
	collections: CreationCollection[];
}

function pickTitle(record: Record<string, unknown>, id: string, col: CreationCollection): string {
	if (col.title) return col.title(record, id);
	const candidates = ['title', 'name', 'path', 'subject', 'label'] as const;
	for (const k of candidates) {
		const v = record[k];
		if (typeof v === 'string' && v.trim()) return v;
	}
	return id;
}

async function expandDocIds(pattern: string, space: string): Promise<string[]> {
	const resolved = pattern.replace(/\{space\}/g, space);
	if (resolved.endsWith('*')) {
		return listDocIds(resolved.slice(0, -1));
	}
	return [resolved];
}

export function createCreationEnumerator(spec: CreationSpec): CreationEnumerator {
	return {
		module: spec.module,
		label: spec.label,
		icon: spec.icon,
		color: spec.color,
		async enumerate({ space, from, to }) {
			const out: Creation[] = [];
			for (const pattern of spec.docPatterns) {
				const docIds = await expandDocIds(pattern, space);
				for (const docId of docIds) {
					const doc = await loadDoc<Record<string, unknown>>(docId);
					if (!doc) continue;
					for (const col of spec.collections) {
						const records = doc[col.path];
						if (!records || typeof records !== 'object') continue;
						const tsField = col.timestampField ?? 'createdAt';
						for (const [id, raw] of Object.entries(records as Record<string, unknown>)) {
							if (!raw || typeof raw !== 'object') continue;
							const rec = raw as Record<string, unknown>;
							if (col.filter && !col.filter(rec)) continue;
							const ts = rec[tsField];
							if (typeof ts !== 'number' || !Number.isFinite(ts)) continue;
							if (from !== undefined && ts < from) continue;
							if (to !== undefined && ts > to) continue;
							const updatedAt = typeof rec.updatedAt === 'number' ? rec.updatedAt as number : undefined;
							out.push({
								createdAt: ts,
								updatedAt,
								title: pickTitle(rec, id, col),
								recordType: col.recordType,
								recordId: id,
								href: col.href?.({ space, docId, id, record: rec }),
								tags: col.tags?.(rec),
								description: col.description?.(rec),
							});
						}
					}
				}
			}
			return out;
		},
	};
}
