import { EventEmitter } from 'events';
import { activityTracker } from './activity-tracker.js';
const emptyState = () => ({
    connected: false,
    windows: [],
    windowSnapshots: [],
    tabs: [],
    messages: [],
    todos: [],
    queuedMessages: [],
    pendingApprovals: [],
    updatedAt: Date.now(),
});
/** Fast path: agent/tab/sidebar working markers must not wait on debounce. */
function workingLanesSignature(state) {
    const aw = state.agentWorking === true ? '1' : state.agentWorking === false ? '0' : '-';
    const tabs = (state.tabs ?? [])
        .map((t) => `${t.id}|${t.composerId ?? ''}|${t.isWorking ? 1 : 0}`)
        .join(';');
    const side = (state.sidebarRepos ?? [])
        .flatMap((r) => r.agents.map((a) => `${a.id}|${a.isWorking ? 1 : 0}`))
        .join(';');
    return `${aw}|${state.agentStatus ?? ''}|${tabs}|${side}`;
}
function sidebarMarkersSignature(state) {
    const tabs = (state.tabs ?? [])
        .map((t) => `${t.id}|${t.isWorking ? 1 : 0}|${t.hasUnread ? 1 : 0}|${t.needsAttention ? 1 : 0}`)
        .join(';');
    const side = (state.sidebarRepos ?? [])
        .flatMap((r) => r.agents.map((a) => `${a.id}|${a.isWorking ? 1 : 0}|${a.hasUnread ? 1 : 0}|${a.needsAttention ? 1 : 0}`))
        .join(';');
    return `${tabs}|${side}`;
}
export class StateManager extends EventEmitter {
    state = emptyState();
    debounceMs;
    debounceTimer = null;
    pendingPatch = {};
    constructor(debounceMs) {
        super();
        this.debounceMs = debounceMs;
    }
    getState() {
        return this.state;
    }
    onExtraction(partial, error) {
        if (!partial) {
            this.queuePatch({ lastError: error, updatedAt: Date.now() });
            return;
        }
        const { pendingQuestionnaire, ...partialRest } = partial;
        const patch = {
            ...partialRest,
            connected: true,
            pendingApprovals: partial.pendingApprovals ?? [],
            pendingQuestionnaire: pendingQuestionnaire ?? null,
            lastError: undefined,
            updatedAt: Date.now(),
        };
        const pqChanged = JSON.stringify(this.state.pendingQuestionnaire ?? null) !==
            JSON.stringify(pendingQuestionnaire ?? null);
        const laneState = {
            agentWorking: patch.agentWorking ?? this.state.agentWorking,
            agentStatus: patch.agentStatus ?? this.state.agentStatus,
            tabs: patch.tabs ?? this.state.tabs,
            sidebarRepos: patch.sidebarRepos ?? this.state.sidebarRepos,
        };
        const workingChanged = workingLanesSignature(this.state) !== workingLanesSignature(laneState);
        const markersChanged = sidebarMarkersSignature(this.state) !== sidebarMarkersSignature(laneState);
        if (pqChanged || workingChanged || markersChanged)
            this.patchNow(patch);
        else
            this.queuePatch(patch);
    }
    onConnectionChanged(connected) {
        this.queuePatch({ connected, updatedAt: Date.now() });
    }
    updateWindows(windows, activeWindowId) {
        this.queuePatch({ windows, activeWindowId, updatedAt: Date.now() });
    }
    updateWindowSnapshots(snapshots) {
        this.queuePatch({ windowSnapshots: snapshots, updatedAt: Date.now() });
    }
    queuePatch(patch) {
        Object.assign(this.pendingPatch, patch);
        if (this.debounceTimer)
            return;
        this.debounceTimer = setTimeout(() => this.flush(), this.debounceMs);
    }
    /** Immediate patch (e.g. after stop_agent) — skips debounce wait. */
    patchNow(patch) {
        Object.assign(this.pendingPatch, patch);
        if (this.debounceTimer) {
            clearTimeout(this.debounceTimer);
            this.debounceTimer = null;
        }
        this.flush();
    }
    flush() {
        this.debounceTimer = null;
        const patch = this.pendingPatch;
        this.pendingPatch = {};
        const resolvedPq = 'pendingQuestionnaire' in patch
            ? patch.pendingQuestionnaire === null
                ? undefined
                : patch.pendingQuestionnaire
            : this.state.pendingQuestionnaire;
        const nextState = {
            ...this.state,
            ...patch,
            pendingQuestionnaire: resolvedPq,
        };
        const diff = {};
        for (const key of Object.keys(patch)) {
            const nextVal = nextState[key];
            const prevVal = this.state[key];
            if (JSON.stringify(nextVal) !== JSON.stringify(prevVal)) {
                if (key === 'pendingQuestionnaire' && nextVal === undefined) {
                    diff.pendingQuestionnaire = null;
                }
                else {
                    diff[key] = nextVal;
                }
            }
        }
        this.state = nextState;
        activityTracker.recordFromState(this.state);
        if (Object.keys(diff).length > 0) {
            this.emit('state:patch', diff);
        }
    }
    emitFull() {
        this.emit('state:full', this.state);
    }
}
