/**
 * docs/nav-renderer.mjs — deterministic generator for
 * `docs/product/README.md` (C49 D-07).
 *
 * Shape we emit, mirroring `.aperant/features/REGISTRY.md` conventions:
 *
 *   # Product Documentation
 *
 *   Last generated: {timestamp}
 *   Features registry last scanned: {registry_last_scanned}
 *
 *   ## Coverage
 *
 *   {coverage-summary table — areas, features documented, stubs, omitted}
 *
 *   ## By Persona
 *
 *   {tier-grouped TOC — primary → secondary → tertiary}
 *
 *   ## By Feature Area
 *
 *   {flat TOC of _shared/<area>/<feature>.md for at-a-glance discovery}
 *
 * No LLM calls. No I/O (caller writes the returned string via
 * atomicWriteText). Pure function — same plan in, same markdown out, so
 * hash-stable regeneration works.
 */

/**
 * @typedef {import('./structure-planner.mjs').StructurePlan} StructurePlan
 * @typedef {import('./structure-planner.mjs').PlannedPersona} PlannedPersona
 */

/**
 * Build the README.md content.
 *
 * @param {Object} inputs
 * @param {StructurePlan} inputs.plan
 * @param {string} [inputs.generatedAt]           ISO timestamp; default = new Date().toISOString()
 * @param {string | null} [inputs.registryLastScanned]   Copied verbatim from
 *                                                       `REGISTRY.md`'s "Last scanned:" line when present.
 * @param {string} [inputs.productName]           Product name for the H1. Defaults to "Product Documentation".
 * @returns {string}
 */
export function renderNavIndex({
	plan,
	generatedAt = new Date().toISOString(),
	registryLastScanned = null,
	productName = null,
}) {
	const title = productName ? `${productName} — Product Documentation` : 'Product Documentation'
	const lines = []
	lines.push(`# ${title}`)
	lines.push('')
	lines.push(`Last generated: ${generatedAt}`)
	if (registryLastScanned) {
		lines.push(`Features registry last scanned: ${registryLastScanned}`)
	}
	lines.push('')
	lines.push('<!-- generator: apt:create-docs (C49) -->')
	lines.push('<!-- regenerate: apt-tools create-docs . -->')
	lines.push('')

	lines.push('## Coverage')
	lines.push('')
	lines.push('| Metric | Count |')
	lines.push('|--------|------:|')
	lines.push(`| Feature areas | ${plan.totals.areas} |`)
	lines.push(`| Features documented (wired) | ${plan.totals.features_documented} |`)
	lines.push(`| Features included as "Coming soon" stubs | ${plan.totals.stubs_included} |`)
	lines.push(`| Features omitted (unwired) | ${plan.totals.features_omitted_unwired} |`)
	lines.push(`| Personas covered | ${plan.personas.length} |`)
	lines.push('')

	lines.push('## By Persona')
	lines.push('')
	const byTier = {
		primary: plan.personas.filter((p) => p.tier === 'primary'),
		secondary: plan.personas.filter((p) => p.tier === 'secondary'),
		tertiary: plan.personas.filter((p) => p.tier === 'tertiary'),
	}
	appendTierSection(lines, 'Primary personas', byTier.primary, plan)
	appendTierSection(lines, 'Secondary personas', byTier.secondary, plan)
	appendTierSection(lines, 'Tertiary personas (skeleton)', byTier.tertiary, plan)

	lines.push('## By Feature Area')
	lines.push('')
	if (plan.areas.length === 0) {
		lines.push('_No feature areas present in the registry. Run `/apt:scan` first._')
		lines.push('')
	} else {
		for (const area of plan.areas) {
			const heading = area.route ? `### ${area.area} (\`${area.route}\`)` : `### ${area.area}`
			lines.push(heading)
			lines.push('')
			lines.push(
				`_Wired: ${area.feature_count_wired} • Stubbed: ${area.feature_count_stubbed} • Unwired (omitted): ${area.feature_count_unwired_omitted}_`,
			)
			lines.push('')
			if (area.features.length === 0) {
				lines.push('_No wired or stubbed features in this area._')
				lines.push('')
				continue
			}
			for (const f of area.features) {
				const marker = f.is_stub ? ' _(Coming soon)_' : ''
				lines.push(`- [${f.feature_name}](${f.shared_path})${marker}`)
			}
			lines.push('')
		}
	}

	lines.push('---')
	lines.push('')
	lines.push(
		'_This index is auto-generated by [`/apt:create-docs`](https://github.com/Mikalsen-AI/aperant-cloud-desktop/tree/main/packages/framework/skills/apt-create-docs). Edits made directly to this file will be overwritten on the next run._',
	)
	lines.push('')

	return lines.join('\n')
}

/**
 * Append one tier section (e.g. "Primary personas") to the running lines array.
 *
 * @param {string[]} lines
 * @param {string} title
 * @param {PlannedPersona[]} personas
 * @param {StructurePlan} plan
 */
function appendTierSection(lines, title, personas, plan) {
	lines.push(`### ${title}`)
	lines.push('')
	if (personas.length === 0) {
		lines.push('_None._')
		lines.push('')
		return
	}
	for (const p of personas) {
		lines.push(`#### [${p.name}](${p.landing_path})`)
		lines.push('')
		// For tertiary we only list area skeletons.
		if (p.tier === 'tertiary') {
			const skeletons = plan.tertiary_skeletons.filter((s) => s.persona_id === p.id)
			if (skeletons.length === 0) {
				lines.push('_No areas registered._')
				lines.push('')
				continue
			}
			for (const s of skeletons) {
				lines.push(`- [${s.area}](${s.path})`)
			}
			lines.push('')
			continue
		}
		// For primary + secondary we list every feature this persona is
		// included on. Variant path wins over shared when both exist.
		// PRF-004: build a Set of this persona's id once outside the areas
		// loop so each feature's included_personas check is O(1) Set.has
		// rather than O(P) Array.includes per feature.
		const personaIdSet = new Set([p.id])
		let anyListed = false
		for (const area of plan.areas) {
			const included = area.features.filter((f) =>
				f.included_personas.some((pid) => personaIdSet.has(pid)),
			)
			if (included.length === 0) continue
			lines.push(`- **${area.area}**`)
			for (const f of included) {
				const path = f.variant_paths[p.id] ?? f.shared_path
				const marker = f.is_stub ? ' _(Coming soon)_' : ''
				lines.push(`  - [${f.feature_name}](${path})${marker}`)
				anyListed = true
			}
		}
		if (!anyListed) {
			lines.push('_No features matched this persona tier._')
		}
		lines.push('')
	}
}
