(() => {
    'use strict';

    window.FotogenicAI = window.FotogenicAI || {};
    window.FotogenicAI.Shared = window.FotogenicAI.Shared || {};

    const DEFAULT_TTL_MS = 10 * 60 * 1000;
    let cache = null;
    let inFlight = null;

    const toFiniteNumber = (value) => {
        if (value === null || typeof value === 'undefined' || value === '') {
            return null;
        }
        const numeric = Number(value);
        return Number.isFinite(numeric) ? numeric : null;
    };

    const normalizeTimestamp = (value, fallback = Date.now()) => {
        const numeric = toFiniteNumber(value);
        if (numeric === null || numeric <= 0) return fallback;
        return numeric < 1e12 ? numeric * 1000 : numeric;
    };

    const normalizeTtl = (meta = {}) => {
        const ttlMs = toFiniteNumber(meta.ttlMs);
        if (ttlMs !== null && ttlMs > 0) return ttlMs;
        const ttlSeconds = toFiniteNumber(meta.ttlSeconds);
        if (ttlSeconds !== null && ttlSeconds > 0) return ttlSeconds * 1000;
        return DEFAULT_TTL_MS;
    };

    const emitUpdate = () => {
        if (typeof window.CustomEvent !== 'function') return;
        window.dispatchEvent(new CustomEvent('fotogenic-ai:credits-updated', {
            detail: getSnapshot({ allowStale: true }),
        }));
    };

    const reportFailure = (operation, code = 'request_failed') => {
        const detail = Object.freeze({
            operation: String(operation || 'request'),
            code: String(code || 'request_failed').replace(/[^a-z0-9_-]/gi, '').toLowerCase() || 'request_failed',
        });
        if (typeof window.CustomEvent === 'function') {
            window.dispatchEvent(new CustomEvent('fotogenic-ai:credits-error', { detail }));
        }
        return detail;
    };

    const readCache = () => cache;

    const writeCache = (payload) => {
        cache = payload;
        emitUpdate();
    };

    const extractBalance = (data) => {
        if (!data || typeof data !== 'object') return null;
        return toFiniteNumber(data.balance);
    };

    const getSnapshot = ({ allowStale = false } = {}) => {
        const current = readCache();
        const balance = toFiniteNumber(current?.balance);
        const fetchedAt = normalizeTimestamp(current?.fetchedAt, 0);
        const ttlMs = normalizeTtl(current || {});
        const ageMs = fetchedAt > 0 ? Math.max(0, Date.now() - fetchedAt) : Number.POSITIVE_INFINITY;
        const isFresh = balance !== null
            && fetchedAt > 0
            && ageMs <= ttlMs
            && current?.provenance !== 'stale'
            && current?.provenance !== 'unavailable'
            && current?.provenance !== 'error';
        return {
            balance: isFresh || allowStale ? balance : null,
            fetchedAt,
            ttlMs,
            ageMs,
            isFresh,
            provenance: isFresh ? 'fresh' : (balance !== null ? 'stale' : (current?.provenance || 'unavailable')),
        };
    };

    const getBalance = (options = {}) => getSnapshot(options).balance;

    const setBalance = (balance, meta = {}) => {
        const numeric = toFiniteNumber(balance);
        if (numeric === null) return null;
        const fetchedAt = normalizeTimestamp(meta.fetchedAt);
        writeCache({
            balance: numeric,
            fetchedAt,
            ttlMs: normalizeTtl(meta),
            provenance: String(meta.provenance || 'fresh'),
        });
        return numeric;
    };

    const clearBalance = (meta = {}) => {
        writeCache({
            balance: null,
            fetchedAt: Date.now(),
            ttlMs: normalizeTtl(meta),
            provenance: String(meta.provenance || 'unavailable'),
        });
    };

    const ensure = (fetchFn, { force = false } = {}) => {
        if (typeof fetchFn !== 'function') return Promise.resolve(null);
        if (!force) {
            const fresh = getBalance();
            if (Number.isFinite(fresh)) return Promise.resolve(fresh);
        }
        if (inFlight) return inFlight;

        inFlight = Promise.resolve()
            .then(fetchFn)
            .then((response) => {
                if (!response?.ok || !response?.data) {
                    reportFailure('refresh', response?.data?.code || 'request_failed');
                    return null;
                }
                const data = response.data;
                const balance = extractBalance(data);
                if (!Number.isFinite(balance)) {
                    reportFailure('refresh', 'invalid_response');
                    return null;
                }
                setBalance(balance, {
                    fetchedAt: data.fetchedAt,
                    ttlSeconds: data.ttlSeconds,
                    provenance: data.provenance || 'fresh',
                });
                return getBalance();
            })
            .catch(() => {
                reportFailure('refresh', 'network_error');
                return null;
            })
            .finally(() => {
                inFlight = null;
            });
        return inFlight;
    };

    window.FotogenicAI.Shared.creditsCache = {
        DEFAULT_TTL_MS,
        extractBalance,
        getBalance,
        getSnapshot,
        setBalance,
        clearBalance,
        ensure,
        reportFailure,
    };
})();
