import { PersistentAssetCache } from "../../features/grid/PersistentAssetCache.js";

const GRID_SNAPSHOT_CACHE = new Map();
const GRID_SNAPSHOT_CACHE_ENABLED = true;
const GRID_SNAPSHOT_CACHE_MAX = 8;
const GRID_SNAPSHOT_STORAGE_ASSET_LIMIT = 200;
const GRID_SNAPSHOT_STORAGE_KEY = "mjr_grid_snapshot_cache_v2";
const GRID_SNAPSHOT_TTL_MS = 30 * 60 * 1000;
const GRID_SNAPSHOT_PERSIST_DEBOUNCE_MS = 1500;

let gridSnapshotStorageLoaded = false;
let gridSnapshotPersistTimer: any = null;
let gridSnapshotPersistPending = false;

function isGridSnapshotCacheEnabled() {
    return GRID_SNAPSHOT_CACHE_ENABLED;
}

function clearStoredGridSnapshots() {
    try {
        GRID_SNAPSHOT_CACHE.clear();
        const storage = gridSnapshotStorage();
        storage?.removeItem?.(GRID_SNAPSHOT_STORAGE_KEY);
        globalThis?.sessionStorage?.removeItem?.(GRID_SNAPSHOT_STORAGE_KEY);
    } catch (e) {
        console.debug?.(e);
    }
}

const GRID_SNAPSHOT_ASSET_FIELDS = [
    "id",
    "filename",
    "name",
    "display_name",
    "filepath",
    "path",
    "fullpath",
    "full_path",
    "file_info",
    "subfolder",
    "source",
    "type",
    "root_id",
    "custom_root_id",
    "kind",
    "ext",
    "size",
    "mtime",
    "generation_time",
    "file_creation_time",
    "created_at",
    "updated_at",
    "indexed_at",
    "width",
    "height",
    "duration",
    "thumbnail_url",
    "thumb_url",
    "preview_url",
    "poster",
    "url",
    "rating",
    "tags",
    "has_workflow",
    "hasWorkflow",
    "has_generation_data",
    "hasGenerationData",
    "workflow_type",
    "workflowType",
    "workflow_id",
    "workflowId",
    "generation_time_ms",
    "positive_prompt",
    "enhanced_caption",
    "auto_tags",
    "has_ai_info",
    "has_ai_vector",
    "has_ai_auto_tags",
    "has_ai_enhanced_caption",
    "job_id",
    "stack_id",
    "source_node_id",
    "source_node_type",
    "date",
    "date_exact",
];

function normalizeSnapshotPart(value: any, fallback = "") {
    try {
        return String(value ?? fallback).trim();
    } catch {
        return String(fallback);
    }
}

export function buildGridSnapshotKey(parts: Record<string, any> = {}): string {
    return JSON.stringify({
        scope: normalizeSnapshotPart(parts.scope || "output", "output"),
        query: normalizeSnapshotPart(parts.query || parts.q || "*", "*"),
        customRootId: normalizeSnapshotPart(parts.customRootId || ""),
        subfolder: normalizeSnapshotPart(parts.subfolder || ""),
        collectionId: normalizeSnapshotPart(parts.collectionId || ""),
        viewScope: normalizeSnapshotPart(parts.viewScope || ""),
        kind: normalizeSnapshotPart(parts.kind || ""),
        workflowOnly: normalizeSnapshotPart(parts.workflowOnly ? "1" : ""),
        minRating: normalizeSnapshotPart(parts.minRating || ""),
        minSizeMB: normalizeSnapshotPart(parts.minSizeMB || ""),
        maxSizeMB: normalizeSnapshotPart(parts.maxSizeMB || ""),
        resolutionCompare: normalizeSnapshotPart(parts.resolutionCompare || ""),
        minWidth: normalizeSnapshotPart(parts.minWidth || ""),
        minHeight: normalizeSnapshotPart(parts.minHeight || ""),
        maxWidth: normalizeSnapshotPart(parts.maxWidth || ""),
        maxHeight: normalizeSnapshotPart(parts.maxHeight || ""),
        workflowType: normalizeSnapshotPart(parts.workflowType || "").toUpperCase(),
        workflowId: normalizeSnapshotPart(parts.workflowId || ""),
        workflowModel: normalizeSnapshotPart(parts.workflowModel || ""),
        workflowRunsOn: normalizeSnapshotPart(parts.workflowRunsOn || "").toLowerCase(),
        dateRange: normalizeSnapshotPart(parts.dateRange || ""),
        dateExact: normalizeSnapshotPart(parts.dateExact || ""),
        sort: normalizeSnapshotPart(parts.sort || "mtime_desc", "mtime_desc"),
        semanticMode: normalizeSnapshotPart(parts.semanticMode ? "1" : ""),
    });
}

export function compactSnapshotAsset(asset: Record<string, any> | null | undefined): Record<string, any> | null {
    if (!asset || typeof asset !== "object") return null;
    const out: Record<string, any> = {};
    for (const field of GRID_SNAPSHOT_ASSET_FIELDS) {
        if (asset[field] !== undefined) out[field] = asset[field];
    }
    if (!out.type && out.source) out.type = out.source;
    if (!out.source && out.type) out.source = out.type;
    if (!out.kind) out.kind = asset.kind || "image";
    if (Array.isArray(out.tags)) out.tags = out.tags.slice(0, 80);
    if (Array.isArray(out.auto_tags)) out.auto_tags = out.auto_tags.slice(0, 80);
    return out;
}

export function normalizeGridSnapshot(snapshot: any) {
    if (!snapshot || typeof snapshot !== "object") return null;
    const at = Number(snapshot.at || 0) || 0;
    if (!at || Date.now() - at > GRID_SNAPSHOT_TTL_MS) return null;
    const assets = Array.isArray(snapshot.assets)
        ? snapshot.assets.map(compactSnapshotAsset).filter(Boolean)
        : [];
    if (!assets.length) return null;
    const totalRaw = Number(snapshot.total ?? assets.length);
    const offsetRaw = Number(snapshot.offset ?? assets.length);
    return {
        assets,
        title: normalizeSnapshotPart(snapshot.title || "Cached", "Cached"),
        at,
        total: Number.isFinite(totalRaw) ? Math.max(0, totalRaw) : assets.length,
        offset: Number.isFinite(offsetRaw) ? Math.max(assets.length, offsetRaw) : assets.length,
        done: !!snapshot.done,
        query: normalizeSnapshotPart(snapshot.query || "*", "*"),
    };
}

function gridSnapshotStorage() {
    try {
        return globalThis?.localStorage || null;
    } catch {
        return null;
    }
}

if (!isGridSnapshotCacheEnabled()) {
    clearStoredGridSnapshots();
}

function migrateLegacySessionSnapshots(storage: any) {
    try {
        const legacy = globalThis?.sessionStorage;
        if (!legacy || !storage) return;
        const raw = legacy.getItem?.(GRID_SNAPSHOT_STORAGE_KEY);
        if (!raw) return;
        if (!storage.getItem?.(GRID_SNAPSHOT_STORAGE_KEY)) {
            storage.setItem(GRID_SNAPSHOT_STORAGE_KEY, raw);
        }
        legacy.removeItem(GRID_SNAPSHOT_STORAGE_KEY);
    } catch (e) {
        console.debug?.(e);
    }
}

function pruneGridSnapshotCache() {
    const now = Date.now();
    for (const [key, snapshot] of GRID_SNAPSHOT_CACHE.entries()) {
        const at = Number(snapshot?.at || 0) || 0;
        if (!at || now - at > GRID_SNAPSHOT_TTL_MS) {
            GRID_SNAPSHOT_CACHE.delete(key);
        }
    }
    while (GRID_SNAPSHOT_CACHE.size > GRID_SNAPSHOT_CACHE_MAX) {
        const oldestKey = GRID_SNAPSHOT_CACHE.keys().next().value;
        if (!oldestKey) break;
        GRID_SNAPSHOT_CACHE.delete(oldestKey);
    }
}

function loadGridSnapshotsFromStorage() {
    if (!isGridSnapshotCacheEnabled()) {
        gridSnapshotStorageLoaded = true;
        clearStoredGridSnapshots();
        return;
    }
    if (gridSnapshotStorageLoaded) return;
    gridSnapshotStorageLoaded = true;
    try {
        const storage = gridSnapshotStorage();
        migrateLegacySessionSnapshots(storage);
        const raw = storage?.getItem?.(GRID_SNAPSHOT_STORAGE_KEY);
        if (!raw) return;
        const parsed = JSON.parse(raw);
        const entries = Array.isArray(parsed?.entries) ? parsed.entries : [];
        for (const entry of entries) {
            if (!Array.isArray(entry) || entry.length < 2) continue;
            const key = String(entry[0] || "");
            const snapshot = normalizeGridSnapshot(entry[1]);
            if (key && snapshot) GRID_SNAPSHOT_CACHE.set(key, snapshot);
        }
        pruneGridSnapshotCache();
    } catch (e) {
        console.debug?.(e);
    }
}

function persistGridSnapshotsToStorageNow() {
    if (!isGridSnapshotCacheEnabled()) {
        clearStoredGridSnapshots();
        return;
    }
    try {
        pruneGridSnapshotCache();
        const storage = gridSnapshotStorage();
        if (!storage) return;
        const entries = Array.from(GRID_SNAPSHOT_CACHE.entries()).map(([key, snapshot]) => [
            key,
            {
                ...snapshot,
                assets: Array.isArray(snapshot?.assets)
                    ? snapshot.assets.slice(0, GRID_SNAPSHOT_STORAGE_ASSET_LIMIT)
                    : [],
            },
        ]);
        storage.setItem(GRID_SNAPSHOT_STORAGE_KEY, JSON.stringify({ entries }));
    } catch (e) {
        console.debug?.(e);
    }
}

function persistGridSnapshotsToStorage() {
    if (!isGridSnapshotCacheEnabled()) {
        clearStoredGridSnapshots();
        gridSnapshotPersistPending = false;
        return;
    }
    gridSnapshotPersistPending = true;
    if (gridSnapshotPersistTimer) return;
    gridSnapshotPersistTimer = setTimeout(() => {
        gridSnapshotPersistTimer = null;
        if (!gridSnapshotPersistPending) return;
        gridSnapshotPersistPending = false;
        persistGridSnapshotsToStorageNow();
    }, GRID_SNAPSHOT_PERSIST_DEBOUNCE_MS);
}

export function flushGridSnapshotsPersist() {
    if (gridSnapshotPersistTimer) {
        clearTimeout(gridSnapshotPersistTimer);
        gridSnapshotPersistTimer = null;
    }
    if (!gridSnapshotPersistPending) return;
    gridSnapshotPersistPending = false;
    persistGridSnapshotsToStorageNow();
}

export function getGridSnapshot(key: any) {
    if (!isGridSnapshotCacheEnabled()) return null;
    loadGridSnapshotsFromStorage();
    const snapshot = normalizeGridSnapshot(GRID_SNAPSHOT_CACHE.get(key));
    if (!snapshot) {
        GRID_SNAPSHOT_CACHE.delete(key);
        persistGridSnapshotsToStorage();
        return null;
    }
    GRID_SNAPSHOT_CACHE.delete(key);
    GRID_SNAPSHOT_CACHE.set(key, snapshot);
    persistGridSnapshotsToStorage();
    return snapshot;
}

export async function getPersistentGridSnapshot(key: any) {
    const memory = getGridSnapshot(key);
    if (memory) return memory;
    const persisted = await PersistentAssetCache.get(String(key || ""));
    const normalized = normalizeGridSnapshot(persisted);
    if (!normalized) return null;
    GRID_SNAPSHOT_CACHE.set(String(key || ""), normalized);
    return normalized;
}

export function hasGridSnapshot(key: string): boolean {
    if (!isGridSnapshotCacheEnabled()) return false;
    loadGridSnapshotsFromStorage();
    return !!normalizeGridSnapshot(GRID_SNAPSHOT_CACHE.get(key));
}

export function rememberGridSnapshot(key: any, snapshot: any) {
    if (!isGridSnapshotCacheEnabled()) return false;
    if (!key || !snapshot || typeof snapshot !== "object") return false;
    const normalized = normalizeGridSnapshot({
        ...snapshot,
        at: snapshot.at || Date.now(),
    });
    if (!normalized) return false;
    GRID_SNAPSHOT_CACHE.delete(key);
    GRID_SNAPSHOT_CACHE.set(key, normalized);
    persistGridSnapshotsToStorage();
    PersistentAssetCache.put(String(key || ""), normalized).catch((e: any) => {
        console.debug?.(e);
    });
    return true;
}

export function resetGridSnapshotCacheForTests() {
    GRID_SNAPSHOT_CACHE.clear();
    gridSnapshotStorageLoaded = false;
    gridSnapshotPersistPending = false;
    if (gridSnapshotPersistTimer) clearTimeout(gridSnapshotPersistTimer);
    gridSnapshotPersistTimer = null;
}
