import * as fs from "node:fs";
import * as path from "node:path";
import { getCustomThemesDir } from "../../../config.js";
import { closeWatcher, isSafeFsWatchPathError, watchWithErrorHandler } from "../../../utils/fs-watch.js";
import { getDefaultTheme } from "./terminal-detection.js";
import { getBuiltinThemes, loadTheme, loadThemeFromPath, setRegisteredTheme } from "./theme-loading.js";
// Use globalThis to share theme across module loaders (tsx + jiti in dev mode)
const THEME_KEY = Symbol.for("@bastani/atomic:theme");
const THEME_KEY_OLD = Symbol.for("@bastani/atomic:theme");
// Export theme as a getter that reads from globalThis
// This ensures all module instances (tsx, jiti) see the same theme
export const theme = new Proxy({}, {
    get(_target, prop) {
        const t = globalThis[THEME_KEY];
        if (!t)
            throw new Error("Theme not initialized. Call initTheme() first.");
        return t[prop];
    },
});
function setGlobalTheme(t) {
    globalThis[THEME_KEY] = t;
    globalThis[THEME_KEY_OLD] = t;
}
let currentThemeName;
let themeWatcher;
let themeReloadTimer;
let themeWatchFilePath;
let themeWatchFileListener;
let onThemeChangeCallback;
export function getCurrentThemeName() {
    return currentThemeName;
}
export function initTheme(themeName, enableWatcher = false) {
    const name = themeName ?? getDefaultTheme();
    currentThemeName = name;
    try {
        setGlobalTheme(loadTheme(name));
        if (enableWatcher) {
            startThemeWatcher();
        }
    }
    catch (_error) {
        // Theme is invalid - fall back to dark theme silently
        currentThemeName = "dark";
        setGlobalTheme(loadTheme("dark"));
        // Don't start watcher for fallback theme
    }
}
export function setTheme(name, enableWatcher = false) {
    currentThemeName = name;
    try {
        setGlobalTheme(loadTheme(name));
        if (enableWatcher) {
            startThemeWatcher();
        }
        if (onThemeChangeCallback) {
            onThemeChangeCallback();
        }
        return { success: true };
    }
    catch (error) {
        // Theme is invalid - fall back to dark theme
        currentThemeName = "dark";
        setGlobalTheme(loadTheme("dark"));
        // Don't start watcher for fallback theme
        return {
            success: false,
            error: error instanceof Error ? error.message : String(error),
        };
    }
}
export function setThemeInstance(themeInstance) {
    setGlobalTheme(themeInstance);
    currentThemeName = "<in-memory>";
    stopThemeWatcher(); // Can't watch a direct instance
    if (onThemeChangeCallback) {
        onThemeChangeCallback();
    }
}
export function onThemeChange(callback) {
    onThemeChangeCallback = callback;
}
function startThemeWatcher() {
    stopThemeWatcher();
    // Only watch if it's a custom theme (not built-in)
    if (!currentThemeName || currentThemeName in getBuiltinThemes()) {
        return;
    }
    const customThemesDir = getCustomThemesDir();
    const watchedThemeName = currentThemeName;
    const watchedFileName = `${watchedThemeName}.json`;
    const themeFile = path.join(customThemesDir, watchedFileName);
    // Only watch if the file exists
    if (!fs.existsSync(themeFile)) {
        return;
    }
    const scheduleReload = () => {
        if (themeReloadTimer) {
            clearTimeout(themeReloadTimer);
        }
        themeReloadTimer = setTimeout(() => {
            themeReloadTimer = undefined;
            // Ignore stale timers after switching themes or stopping the watcher
            if (currentThemeName !== watchedThemeName) {
                return;
            }
            // Keep the last successfully loaded theme active if the file is temporarily missing
            if (!fs.existsSync(themeFile)) {
                return;
            }
            try {
                // Reload the theme from disk and refresh the registry cache
                const reloadedTheme = loadThemeFromPath(themeFile);
                setRegisteredTheme(watchedThemeName, reloadedTheme);
                setGlobalTheme(reloadedTheme);
                // Notify callback (to invalidate UI)
                if (onThemeChangeCallback) {
                    onThemeChangeCallback();
                }
            }
            catch (_error) {
                // Ignore errors (file might be in invalid state while being edited)
            }
        }, 100);
    };
    const startPollingFallback = () => {
        if (themeWatchFilePath && themeWatchFileListener) {
            return;
        }
        themeWatchFilePath = themeFile;
        themeWatchFileListener = (current, previous) => {
            if (current.mtimeMs !== previous.mtimeMs ||
                current.ctimeMs !== previous.ctimeMs ||
                current.size !== previous.size) {
                scheduleReload();
            }
        };
        fs.watchFile(themeFile, { interval: 1000 }, themeWatchFileListener);
    };
    themeWatcher =
        watchWithErrorHandler(customThemesDir, (_eventType, filename) => {
            if (currentThemeName !== watchedThemeName) {
                return;
            }
            if (!filename) {
                scheduleReload();
                return;
            }
            if (filename !== watchedFileName) {
                return;
            }
            scheduleReload();
        }, (error) => {
            closeWatcher(themeWatcher);
            themeWatcher = undefined;
            if (isSafeFsWatchPathError(error)) {
                startPollingFallback();
            }
        }) ?? undefined;
}
export function stopThemeWatcher() {
    if (themeReloadTimer) {
        clearTimeout(themeReloadTimer);
        themeReloadTimer = undefined;
    }
    closeWatcher(themeWatcher);
    themeWatcher = undefined;
    if (themeWatchFilePath && themeWatchFileListener) {
        fs.unwatchFile(themeWatchFilePath, themeWatchFileListener);
    }
    themeWatchFilePath = undefined;
    themeWatchFileListener = undefined;
}
//# sourceMappingURL=global-theme.js.map