/**
 * UiState Builder
 * Phase 3: Merge collector results into single UiState snapshot
 */
import { collectPosture } from '../collectors/collector_posture.js';
import { collectNetwork } from '../collectors/collector_network.js';
import { collectResources } from '../collectors/collector_resources.js';
import { collectAssets } from '../collectors/collector_assets.js';
import { collectCapabilities } from '../collectors/collector_capabilities.js';
import { collectFeed } from '../collectors/collector_feed.js';
import { collectGeo } from '../collectors/collector_geo.js';
import { historyStore } from './historyStore.js';
import { setCollectorResults } from './getCollectorResults.js';
// Cache for expensive collectors
let cachedNetwork = null;
const NETWORK_CACHE_MS = 30000; // 30 seconds
/**
 * Build UiState from collectors
 * Pure-ish and testable
 */
export async function buildUiState(appState) {
    const now = Date.now();
    // Collect all data (some cached, some fresh)
    const [postureResult, networkResult, resourcesResult, assetsResult, capabilitiesResult, feedResult, geoResult,] = await Promise.all([
        collectPosture(appState),
        (async () => {
            // Cache network collector (expensive)
            if (cachedNetwork && (now - cachedNetwork.ts) < NETWORK_CACHE_MS) {
                return cachedNetwork.result;
            }
            const result = await collectNetwork(appState);
            cachedNetwork = { result, ts: now };
            return result;
        })(),
        collectResources(),
        collectAssets(appState),
        collectCapabilities(appState),
        collectFeed(),
        collectGeo(appState),
    ]);
    // Phase 9: Calculate freshness from asOf (new contract) or ts (legacy)
    const freshness = {
        posture: (now - (postureResult.asOf || postureResult.ts || now)) < postureResult.staleAfterMs ? "FRESH" : "STALE",
        network: (now - (networkResult.asOf || networkResult.ts || now)) < networkResult.staleAfterMs ? "FRESH" : "STALE",
        resources: (now - (resourcesResult.asOf || resourcesResult.ts || now)) < resourcesResult.staleAfterMs ? "FRESH" : "STALE",
        assets: (now - (assetsResult.asOf || assetsResult.ts || now)) < assetsResult.staleAfterMs ? "FRESH" : "STALE",
        capabilities: (now - (capabilitiesResult.asOf || capabilitiesResult.ts || now)) < capabilitiesResult.staleAfterMs ? "FRESH" : "STALE",
    };
    // Phase 9: Store collector results for validation
    const resultsMap = new Map();
    resultsMap.set('posture', postureResult);
    resultsMap.set('network', networkResult);
    resultsMap.set('resources', resourcesResult);
    resultsMap.set('assets', assetsResult);
    resultsMap.set('capabilities', capabilitiesResult);
    resultsMap.set('feed', feedResult);
    resultsMap.set('geo', geoResult);
    setCollectorResults(resultsMap);
    // Phase 9: Validate collector results before building UiState
    // Check that all collectors have status and asOf
    const collectorResults = [
        { name: 'posture', result: postureResult },
        { name: 'network', result: networkResult },
        { name: 'resources', result: resourcesResult },
        { name: 'assets', result: assetsResult },
        { name: 'capabilities', result: capabilitiesResult },
        { name: 'feed', result: feedResult },
        { name: 'geo', result: geoResult },
    ];
    const invalidCollectors = collectorResults.filter(cr => !cr.result.status || !cr.result.asOf);
    if (invalidCollectors.length > 0) {
        // If in dev, throw; otherwise, log and continue with degraded state
        const errorMsg = `Collector validation failed: ${invalidCollectors.map(c => c.name).join(', ')}`;
        if (process.env.NODE_ENV === 'development' || process.env.DEV === '1') {
            throw new Error(errorMsg);
        }
        else {
            console.error(`[SAFE HOLD] ${errorMsg}`);
        }
    }
    // Get history for sparklines
    const history = {
        cpu: historyStore.getSamples('cpu'),
        ram: historyStore.getSamples('ram'),
        latency: historyStore.getSamples('latency'),
    };
    // Phase 9: Build UiState (only include data if status is LIVE or STALE)
    const uiState = {
        ts: now,
        posture: (postureResult.status === 'LIVE' || postureResult.status === 'STALE')
            ? postureResult.data
            : {
                posture: 'UNKNOWN',
                risk: 'UNKNOWN',
                connected: 'UNKNOWN',
                target: 'UNKNOWN',
                lastChange: 'UNKNOWN',
                cause: 'UNKNOWN',
                dependencies: {
                    config: 'UNKNOWN',
                    gateway: 'UNKNOWN',
                    database: 'UNKNOWN',
                    registry: 'UNKNOWN',
                },
            },
        network: (networkResult.status === 'LIVE' || networkResult.status === 'STALE')
            ? networkResult.data
            : {
                originRegion: 'UNKNOWN',
                originClass: 'UNKNOWN',
                gatewayRegion: 'UNKNOWN',
                dbRegion: 'UNKNOWN',
                latencyMs: 'UNKNOWN',
                latencyClass: 'UNKNOWN',
                publicIpMasked: 'UNKNOWN',
            },
        resources: (resourcesResult.status === 'LIVE' || resourcesResult.status === 'STALE')
            ? resourcesResult.data
            : {
                cpuPercent: 'UNKNOWN',
                load1m: 'UNKNOWN',
                ramUsedMb: 'UNKNOWN',
                ramTotalMb: 'UNKNOWN',
                diskUsedGb: 'UNKNOWN',
                diskTotalGb: 'UNKNOWN',
                uptimeSec: 'UNKNOWN',
                procCount: 'UNKNOWN',
            },
        assets: (assetsResult.status === 'LIVE' || assetsResult.status === 'STALE')
            ? assetsResult.data
            : {
                total: 'UNKNOWN',
                active: 'UNKNOWN',
                idle: 'UNKNOWN',
                error: 'UNKNOWN',
                highlight: 'UNKNOWN',
                lastAction: 'UNKNOWN',
            },
        capabilities: (capabilitiesResult.status === 'LIVE' || capabilitiesResult.status === 'STALE')
            ? capabilitiesResult.data
            : {
                gateway: 'UNKNOWN',
                database: 'UNKNOWN',
                memory: 'UNKNOWN',
                security: 'UNKNOWN',
                rateLimit: 'UNKNOWN',
            },
        feed: (feedResult.status === 'LIVE' || feedResult.status === 'STALE')
            ? feedResult.data
            : { events: [] },
        geo: (geoResult.status === 'LIVE' || geoResult.status === 'STALE')
            ? geoResult.data
            : {
                originLabel: 'UNKNOWN',
                originRegion: 'UNKNOWN',
                gatewayRegion: 'UNKNOWN',
                dbRegion: 'UNKNOWN',
                routeLabel: 'UNKNOWN',
                pingMs: 'UNKNOWN',
                pingClass: 'UNKNOWN',
                confidence: 'UNKNOWN',
                source: 'NONE',
            },
        freshness,
        history,
    };
    return uiState;
}
//# sourceMappingURL=uiStateBuilder.js.map