import { computed, shallowReactive } from "vue";

function normalizeIds(value: any) {
    return Array.from(value || [])
        .map((id) => String(id || "").trim())
        .filter(Boolean);
}

export function useGridState() {
    const state = shallowReactive({
        query: "*",
        offset: 0,
        cursor: null as any,
        total: null as number | null,
        loading: false,
        done: false,
        seenKeys: new Set(),
        assets: [] as any[],
        assetIdSet: new Set(),
        filenameCounts: new Map(),
        nonImageSiblingKeys: new Set(),
        stemMap: new Map(),
        renderedFilenameMap: new Map(),
        hiddenPngSiblings: 0,
        requestId: 0,
        abortController: null,
        loadingMessage: "",
        statusMessage: "",
        statusError: false,
        selectedIds: [] as string[],
        activeId: "",
        selectionAnchorId: "",
        cardElements: new Map(),
        virtualGrid: null as any,
    });

    state.virtualGrid = {
        setItems(items: any) {
            state.assets = Array.isArray(items) ? items.slice() : [];
        },
    };

    const selectedIdSet = computed(() => new Set(normalizeIds(state.selectedIds)));

    function setStatusMessage(message = "", { error = false } = {}) {
        state.statusMessage = String(message || "");
        state.statusError = !!error;
    }

    function clearStatusMessage() {
        state.statusMessage = "";
        state.statusError = false;
    }

    function clearLoadingMessage() {
        state.loadingMessage = "";
    }

    function setLoadingMessage(message = "") {
        state.loadingMessage = String(message || "");
    }

    function resetCollections() {
        state.seenKeys = new Set();
        state.assetIdSet = new Set();
        state.filenameCounts = new Map();
        state.nonImageSiblingKeys = new Set();
        state.stemMap = new Map();
        state.renderedFilenameMap = new Map();
        state.hiddenPngSiblings = 0;
    }

    function resetAssets({ query = "*", total = null, done = false } = {}) {
        state.query = String(query || "*") || "*";
        state.offset = 0;
        state.cursor = null;
        state.total = total == null ? null : Number(total) || 0;
        state.done = !!done;
        state.assets = [];
        resetCollections();
    }

    function setSelection(ids: any, activeId = "", { preserveAnchor = false } = {}) {
        const nextIds = Array.from(new Set(normalizeIds(ids)));
        const nextActive = String(activeId || nextIds[0] || "").trim();
        state.selectedIds = nextIds;
        state.activeId = nextActive;
        if (!preserveAnchor) {
            if (nextActive) {
                state.selectionAnchorId = nextActive;
            } else if (!nextIds.length) {
                state.selectionAnchorId = "";
            }
        }
        return {
            selectedIds: nextIds,
            activeId: nextActive,
        };
    }

    function reconcileSelection(visibleAssetIds: any, { activeId = "" } = {}) {
        const visible = new Set(normalizeIds(visibleAssetIds));
        const nextIds = normalizeIds(state.selectedIds).filter((id) => visible.has(id));
        const nextActive = String(activeId || state.activeId || nextIds[0] || "").trim();
        const resolvedActive = visible.has(nextActive) ? nextActive : nextIds[0] || "";
        // Pruning visible assets must not reset the Shift+Click anchor.
        return setSelection(nextIds, resolvedActive, { preserveAnchor: true });
    }

    function getSelectedAssets() {
        const selected = selectedIdSet.value;
        return (Array.isArray(state.assets) ? state.assets : []).filter((asset) =>
            selected.has(String(asset?.id || "")),
        );
    }

    function getActiveAsset() {
        const activeId = String(state.activeId || "").trim();
        if (activeId) {
            const found = (Array.isArray(state.assets) ? state.assets : []).find(
                (asset) => String(asset?.id || "") === activeId,
            );
            if (found) return found;
        }
        return getSelectedAssets()[0] || null;
    }

    return {
        state,
        selectedIdSet,
        setLoadingMessage,
        clearLoadingMessage,
        setStatusMessage,
        clearStatusMessage,
        resetCollections,
        resetAssets,
        setSelection,
        reconcileSelection,
        getSelectedAssets,
        getActiveAsset,
    };
}
