/**
 * Policy diagnostics panel data provider.
 *
 * Wraps a `PolicyRegistry` and optionally a `DivergencePanel` to expose
 * combined policy state (current bundle, candidate, simulation status,
 * divergence trends) for the diagnostics view.
 *
 * This panel is push-passive: it does not drive timers. Callers must
 * call `recordTrendEntry()` periodically if a divergence panel is attached.
 */
import { PolicyRegistry } from '../../permissions/policy-registry.js';
import { DEFAULT_COMPONENT_CONFIG } from '../types.js';
import { logger } from '../../../utils/logger.js';
import { summarizeError } from '../../../utils/error-display.js';
/**
 * PolicyPanel — diagnostics data provider for the policy registry.
 *
 * Usage:
 * ```ts
 * const registry = new PolicyRegistry();
 * const panel = new PolicyPanel(registry, divergencePanel);
 *
 * panel.subscribe(() => {
 *   const snap = panel.getSnapshot();
 *   render(snap);
 * });
 *
 * // Notify when the registry state changes:
 * panel.notify();
 *
 * // On cleanup:
 * panel.dispose();
 * ```
 */
export class PolicyPanel {
    _registry;
    _divergencePanel;
    _config;
    _recentPermissionAudit;
    _lintFindings;
    _lastSimulationSummary;
    _lastPreflightReview;
    _subscribers = new Set();
    constructor(registry, divergencePanel = null, recentPermissionAudit = [], lintFindings = [], lastSimulationSummary = null, lastPreflightReview = null, config = DEFAULT_COMPONENT_CONFIG) {
        this._registry = registry;
        this._divergencePanel = divergencePanel;
        this._recentPermissionAudit = recentPermissionAudit;
        this._lintFindings = lintFindings;
        this._lastSimulationSummary = lastSimulationSummary;
        this._lastPreflightReview = lastPreflightReview;
        this._config = config;
    }
    /**
     * recordTrendEntry — Forwards to the attached DivergencePanel if present.
     *
     * Call periodically (e.g. every 30 seconds) while simulation is active.
     */
    recordTrendEntry() {
        this._divergencePanel?.recordTrendEntry();
        this._notify();
    }
    /**
     * notify — Trigger a subscriber notification.
     *
     * Call after registry state changes (load, promote, rollback) so the
     * diagnostics view can re-render.
     */
    notify() {
        this._notify();
    }
    /**
     * getSnapshot — Returns the current combined policy + divergence snapshot.
     */
    getSnapshot() {
        const current = this._registry.getCurrent();
        const candidate = this._registry.getCandidate();
        const rawHistory = this._registry.getHistory();
        // Most recent first, capped for display
        const history = rawHistory
            .slice()
            .reverse()
            .slice(0, this._config.bufferLimit);
        const diff = this._registry.diff();
        let divergence = null;
        if (this._divergencePanel) {
            divergence = this._divergencePanel.getSnapshot();
        }
        return {
            current,
            candidate,
            history,
            diff,
            divergence,
            recentPermissionAudit: this._recentPermissionAudit.slice(0, this._config.bufferLimit),
            lintFindings: this._lintFindings.slice(0, this._config.bufferLimit),
            lastSimulationSummary: this._lastSimulationSummary,
            lastPreflightReview: this._lastPreflightReview,
            capturedAt: new Date().toISOString(),
        };
    }
    /**
     * Register a callback invoked whenever the panel state changes.
     * @returns An unsubscribe function.
     */
    subscribe(callback) {
        this._subscribers.add(callback);
        return () => this._subscribers.delete(callback);
    }
    /**
     * Release all subscriptions.
     */
    dispose() {
        this._subscribers.clear();
    }
    _notify() {
        for (const cb of this._subscribers) {
            try {
                cb();
            }
            catch (err) {
                logger.warn('[PolicyPanel] subscriber error', { error: summarizeError(err) });
            }
        }
    }
}
