// Planu — Portal regenerator: auto-regen pages when stores change (SPEC-146)
import { mkdir, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { hashProjectPath } from '../../../storage/base-store.js';
import { getAffectedPages } from './dirty-flag-map.js';
import { withAudit } from '../../../engine/autopilot/audit-logger.js';
// Debounce state keyed by projectPath to avoid cross-project interference
const debounceTimers = new Map();
const pendingStoresPerProject = new Map();
/**
 * Schedule a debounced regeneration (500 ms window).
 * Multiple calls within the window are coalesced per project.
 */
export function scheduleRegeneration(projectPath, changedStores) {
    const pending = pendingStoresPerProject.get(projectPath) ?? new Set();
    for (const s of changedStores) {
        pending.add(s);
    }
    pendingStoresPerProject.set(projectPath, pending);
    const existing = debounceTimers.get(projectPath);
    if (existing) {
        clearTimeout(existing);
    }
    const timer = setTimeout(() => {
        const stores = [...pending];
        pendingStoresPerProject.delete(projectPath);
        debounceTimers.delete(projectPath);
        regeneratePages(projectPath, stores).catch((err) => {
            const message = err instanceof Error ? err.message : String(err);
            console.error('[Planu] Portal regeneration failed for', projectPath, ':', message);
        });
    }, 500);
    debounceTimers.set(projectPath, timer);
}
/**
 * Immediately regenerate all portal pages affected by the given store changes.
 * Creates planu/ directory if it does not exist.
 * Returns the list of page keys that were successfully written.
 * Never throws.
 */
export async function regeneratePages(projectPath, changedStores) {
    const planuDir = join(projectPath, 'planu');
    try {
        await mkdir(planuDir, { recursive: true });
    }
    catch {
        return [];
    }
    const pages = getAffectedPages(changedStores);
    const regenerated = [];
    for (const page of pages) {
        try {
            await withAudit(projectPath, 'portal_regeneration', `regeneratePage(${page})`, async () => {
                const html = await generatePage(projectPath, page);
                if (html) {
                    const filename = page === 'index' ? 'index.html' : `${page}.html`;
                    const filePath = join(planuDir, filename);
                    await writeFile(filePath, html, 'utf-8');
                    regenerated.push(page);
                }
            });
        }
        catch {
            // Silent — never fail the parent tool
        }
    }
    return regenerated;
}
/**
 * Generate HTML for a single portal page by loading required data from stores.
 * Returns null when data is insufficient or generation fails.
 * Loads specs once and shares across all page generators that need them.
 */
async function generatePage(projectPath, page) {
    const projectId = hashProjectPath(projectPath);
    try {
        const { listSpecs } = await import('../../../storage/spec-store.js');
        const specs = await listSpecs(projectId);
        return await dispatchPageGenerator(projectPath, projectId, page, specs);
    }
    catch {
        return null;
    }
}
async function dispatchPageGenerator(projectPath, projectId, page, specs) {
    switch (page) {
        case 'index': {
            const { regenerateSpecSummaryHtml } = await import('../../spec-summary-html.js');
            await regenerateSpecSummaryHtml(projectPath, specs);
            return null; // regenerateSpecSummaryHtml writes directly
        }
        case 'executive-summary': {
            const { getKnowledge } = await import('../../../storage/knowledge-store.js');
            const { generateExecutiveSummary } = await import('../executive-summary/executive-summary-generator.js');
            const knowledge = await getKnowledge(projectId);
            if (!knowledge) {
                return null;
            }
            const doc = generateExecutiveSummary(knowledge, specs, 'en');
            return doc.content;
        }
        case 'analytics': {
            const { generateAnalyticsPage } = await import('./analytics-page.js');
            return generateAnalyticsPage(specs);
        }
        case 'roadmap': {
            const { generateRoadmapPage } = await import('./roadmap-page.js');
            return generateRoadmapPage(specs);
        }
        case 'risks': {
            const { loadAllRiskRegisters } = await import('../../../storage/risk-store.js');
            const { generateRiskPage } = await import('./risk-page.js');
            const { projectDataDir } = await import('../../../storage/base-store.js');
            const dataDir = projectDataDir(projectId);
            const risks = await loadAllRiskRegisters(dataDir);
            return generateRiskPage(risks, specs);
        }
        case 'decisions': {
            const { getDecisions } = await import('../../../storage/decision-store.js');
            const { generateDecisionPage } = await import('./decision-page.js');
            const decisions = await getDecisions(projectId);
            return generateDecisionPage(decisions);
        }
        case 'architecture': {
            const { getKnowledge } = await import('../../../storage/knowledge-store.js');
            const { generateArchitecturePage } = await import('./architecture-page.js');
            const knowledge = await getKnowledge(projectId);
            if (!knowledge) {
                return null;
            }
            return generateArchitecturePage(knowledge);
        }
        case 'changelog': {
            const { generateChangelogPage } = await import('./changelog-page.js');
            return generateChangelogPage(specs);
        }
    }
}
//# sourceMappingURL=portal-regenerator.js.map