// Per-thread state type, transition functions, and selectors.
// All transitions operate on the global store from ../store.js.
//
// ThreadRunState is a value-type: one entry per active thread in the
// global store's `threads` Map. Transition functions produce new Map +
// new ThreadRunState objects each time (immutable updates).
//
// Derived helpers (queue checks) compute from state and are never
// stored — they are always re-derived from ThreadRunState.
//
// STATE DISCIPLINE: keep as little state as possible. Before adding any new
// state field, ask if it can be derived from existing state instead.
import { store } from '../store.js';
// ── Initial state factory ────────────────────────────────────────
export function initialThreadState() {
    return {
        sessionId: undefined,
        queueItems: [],
        listenerController: undefined,
        sentPartIds: new Set(),
    };
}
// ── Derived helpers (compute, never store) ───────────────────────
export function hasQueue(t) {
    return t.queueItems.length > 0;
}
// ── Pure transition helpers ──────────────────────────────────────
// Immutable: produces new Map + new ThreadRunState object each time.
export function updateThread(threadId, updater) {
    store.setState((s) => {
        const existing = s.threads.get(threadId);
        if (!existing) {
            return s;
        }
        const newThreads = new Map(s.threads);
        newThreads.set(threadId, updater(existing));
        return { threads: newThreads };
    });
}
export function ensureThread(threadId) {
    if (store.getState().threads.has(threadId)) {
        return;
    }
    store.setState((s) => {
        const newThreads = new Map(s.threads);
        newThreads.set(threadId, initialThreadState());
        return { threads: newThreads };
    });
}
export function removeThread(threadId) {
    store.setState((s) => {
        if (!s.threads.has(threadId)) {
            return s;
        }
        const newThreads = new Map(s.threads);
        newThreads.delete(threadId);
        return { threads: newThreads };
    });
}
export function setSessionId(threadId, sessionId) {
    updateThread(threadId, (t) => ({ ...t, sessionId }));
}
export function enqueueItem(threadId, item) {
    updateThread(threadId, (t) => ({
        ...t,
        queueItems: [...t.queueItems, item],
    }));
}
// Atomic dequeue: read + write in one setState call to prevent
// a concurrent enqueue between read and write from losing items.
export function dequeueItem(threadId) {
    let next;
    store.setState((s) => {
        const t = s.threads.get(threadId);
        if (!t || t.queueItems.length === 0) {
            return s;
        }
        const [head, ...rest] = t.queueItems;
        next = head;
        const newThreads = new Map(s.threads);
        newThreads.set(threadId, { ...t, queueItems: rest });
        return { threads: newThreads };
    });
    return next;
}
export function clearQueueItems(threadId) {
    updateThread(threadId, (t) => ({ ...t, queueItems: [] }));
}
// ── Queries ──────────────────────────────────────────────────────
export function getThreadState(threadId) {
    return store.getState().threads.get(threadId);
}
export function getThreadIds() {
    return [...store.getState().threads.keys()];
}
