/**
 * Unified polling for long-running server operations (Sitefinity init, imports, mapping edit).
 * One timer; multiple subscribers and per-operation watchers.
 */
(function (global) {
    var POLL_MS = 2000;
    var timer = null;
    var subscribers = new Set();
    var watchers = new Map();
    var snapshot = { operations: [], runningImports: [], mappingStatuses: {} };
    var opById = {};

    function pick(obj, camel, pascal) {
        if (!obj) return undefined;
        if (obj[camel] !== undefined) return obj[camel];
        return obj[pascal];
    }

    function applySnapshot(data) {
        snapshot.operations = pick(data, "operations", "Operations") || [];
        snapshot.runningImports = pick(data, "runningImports", "RunningImports") || [];
        snapshot.mappingStatuses = pick(data, "mappingStatuses", "MappingStatuses") || {};
        opById = {};
        snapshot.operations.forEach(function (o) {
            var id = pick(o, "id", "Id");
            if (id) opById[id] = o;
        });
        subscribers.forEach(function (fn) {
            try { fn(snapshot, opById); } catch (e) { console.error("LongRunningOps subscriber", e); }
        });
        watchers.forEach(function (cb, id) {
            try { cb(opById[id] || null, snapshot); } catch (e) { console.error("LongRunningOps watcher", e); }
        });
    }

    async function poll(mappingIds) {
        try {
            var url = "/api/Operations/GetSnapshot";
            if (mappingIds && mappingIds.length)
                url += "?mappingIds=" + encodeURIComponent(mappingIds.join(","));
            var r = await fetch(url);
            if (r.ok) {
                var data = await r.json();
                applySnapshot(data);
            }
        } catch (e) {
            /* ignore transient network errors */
        }
    }

    function ensurePolling(getMappingIds) {
        if (timer) return;
        var tick = function () {
            var ids = typeof getMappingIds === "function" ? getMappingIds() : [];
            poll(ids);
        };
        tick();
        timer = setInterval(tick, POLL_MS);
    }

    function stopPollingIfIdle() {
        if (subscribers.size === 0 && watchers.size === 0 && timer) {
            clearInterval(timer);
            timer = null;
        }
    }

    global.LongRunningOps = {
        POLL_MS: POLL_MS,

        ids: {
            sitefinityInit: function (connectionId) { return "sitefinity-init:" + connectionId; },
            importRun: function (runId) { return "import-run:" + runId; },
            importMapping: function (mappingId) { return "import-mapping:" + mappingId; },
            mappingEdit: function (mappingId) { return "mapping-edit:" + mappingId; }
        },

        kinds: {
            SitefinityInit: "SitefinityInit",
            Import: "Import",
            MappingEdit: "MappingEdit"
        },

        getSnapshot: function () { return snapshot; },

        get: function (id) { return opById[id] || null; },

        operationMessage: function (op) {
            if (!op) return "";
            var msg = pick(op, "message", "Message") || "";
            var kind = pick(op, "kind", "Kind") || "";
            if (kind === "SitefinityInit" || kind === "MappingEdit")
                return msg;
            if (kind === "Import" && (msg.indexOf("Importing item ") >= 0 || msg.indexOf("Discovering source") >= 0 || msg.indexOf("Importing ") === 0))
                return msg;
            var cur = pick(op, "current", "Current");
            var tot = pick(op, "total", "Total");
            if (cur != null && tot != null && tot > 0)
                msg += " (" + cur + " / " + tot + ")";
            var det = pick(op, "detail", "Detail");
            if (det) msg += (msg ? " — " : "") + det;
            return msg;
        },

        /**
         * Subscribe to all snapshot updates. getMappingIds() is called each poll (optional).
         * Returns unsubscribe function.
         */
        subscribe: function (callback, getMappingIds) {
            subscribers.add(callback);
            ensurePolling(getMappingIds);
            callback(snapshot, opById);
            return function () {
                subscribers.delete(callback);
                stopPollingIfIdle();
            };
        },

        /**
         * Watch a single operation id (e.g. mapping-edit:5). Returns unsubscribe.
         */
        watch: function (operationId, callback, getMappingIds) {
            watchers.set(operationId, callback);
            ensurePolling(getMappingIds);
            callback(opById[operationId] || null, snapshot);
            return function () {
                watchers.delete(operationId);
                stopPollingIfIdle();
            };
        },

        forceRefresh: function (getMappingIds) {
            var ids = typeof getMappingIds === "function" ? getMappingIds() : [];
            return poll(ids);
        }
    };
})(typeof window !== "undefined" ? window : this);
