<?php
// components/ConfigStore.php
// Facade for configuration and status across providers (mock/live)

namespace Components;

class ConfigStore
{
    private const STORE_FILE = 'var/config_store.json';
    private const MODULE_CONFIG_KEY = 'module_config';

    protected static array $moduleConfigCache = [];
    protected static array $moduleStatusCache = [];
    protected static array $isConfiguredCache = [];
    protected static ?array $allStatusesCache = null;
    protected static ?array $uiOpenMapCache = null;
    protected static ?array $columnStateMapCache = null;
    protected static array $listLayoutCache = [];
    protected static array $listGroupedCache = [];
    protected static array $listPerPageCache = [];
    protected static array $newsletterUiStateCache = [];
    protected static array $viewModeCache = [];
    protected static array $performanceTimeframeCache = [];
    protected static ?string $calendarFeedTokenCache = null;
    protected static ?array $allConfigsCache = null;

    /** Resolve absolute path to store file and ensure directory exists */
    private static function storePath(): string
    {
        $root = defined('BEEZUI_ROOT') ? BEEZUI_ROOT : dirname(__DIR__);
        $path = $root . DIRECTORY_SEPARATOR . self::STORE_FILE;
        $dir = dirname($path);
        if (!is_dir($dir)) {
            @mkdir($dir, 0775, true);
        }
        return $path;
    }

    /** Read entire store (associative array); return [] if missing or invalid */
    private static function readStore(): array
    {
        $path = self::storePath();
        if (!is_file($path)) {
            return [];
        }
        $json = @file_get_contents($path);
        if ($json === false || $json === '') {
            return [];
        }
        $data = json_decode($json, true);
        return is_array($data) ? $data : [];
    }

    /** Write entire store atomically; ignore errors silently */
    private static function writeStore(array $store): void
    {
        $path = self::storePath();
        $json = json_encode($store, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        if ($json === false) {
            return; // nothing we can do
        }
        @file_put_contents($path, $json, LOCK_EX);
    }

    /** Return full config map: module => values */
    public static function getAllConfigs(): array
    {
        return self::$allConfigsCache ??= \Components\Data\DataRegistry::config()->getAllConfigs();
    }

    /** Return module config values (assoc array); [] if none */
    public static function getModuleConfig(string $module): array
    {
        return self::$moduleConfigCache[$module]
            ??= \Components\Data\DataRegistry::config()->getModuleConfig($module);
    }

    /** Persist module config values */
    public static function setModuleConfig(string $module, array $values, bool $processOnlyGivenFields = false): void
    {
        \Components\Data\DataRegistry::config()->setModuleConfig($module, $values, $processOnlyGivenFields);
        unset(self::$moduleConfigCache[$module]);
        unset(self::$moduleStatusCache[$module]);
        self::$allStatusesCache = null;
        self::$allConfigsCache = null;
    }

    /** Return full status map derived from module_config: module => 'on'|'' */
    public static function getAllStatuses(): array
    {
        return self::$allStatusesCache ??= \Components\Data\DataRegistry::config()->getAllStatuses();
    }

    /** Return true if module is ON */
    public static function isModuleOn(string $module): bool
    {
        return self::$moduleStatusCache[$module]
            ??= \Components\Data\DataRegistry::config()->isModuleOn($module);
    }

    /** Set module status on/off, stored as *_STATUS inside module_config */
    public static function setModuleStatus(string $module, bool $on): void
    {
        \Components\Data\DataRegistry::config()->setModuleStatus($module, $on);
        self::$moduleStatusCache[$module] = $on;
        unset(self::$moduleConfigCache[$module]);
        self::$allStatusesCache = null;
        self::$allConfigsCache = null;
    }

    /**
     * UI open state map: module => bool
     * Returns associative array suitable for Alpine initialization
     */
    public static function getUiOpenMap(): array
    {
        return self::$uiOpenMapCache ??= \Components\Data\DataRegistry::config()->getUiOpenMap();
    }

    /** Persist a single module UI open/closed state. */
    public static function setUiOpenState(string $module, bool $open): void
    {
        \Components\Data\DataRegistry::config()->setUiOpenState($module, $open);
        if (self::$uiOpenMapCache !== null) {
            self::$uiOpenMapCache[$module] = $open;
        }
    }

    /**
     * Column visibility map: key => bool
     * Returns associative array suitable for Alpine initialization
     */
    public static function getColumnStateMap(): array
    {
        return self::$columnStateMapCache ??= \Components\Data\DataRegistry::config()->getColumnStateMap();
    }

    /** Persist a single column visibility state. */
    public static function setColumnState(string $key, bool $visible): void
    {
        \Components\Data\DataRegistry::config()->setColumnState($key, $visible);
        if (self::$columnStateMapCache !== null) {
            self::$columnStateMapCache[$key] = $visible;
        }
    }

    /** Optional: list known config keys for a module */
    public static function listKeys(string $module): array
    {
        return \Components\Data\DataRegistry::config()->listKeys($module);
    }

    /** Return true if the module configuration has been saved at least once. */
    public static function isConfigured(string $module): bool
    {
        return self::$isConfiguredCache[$module]
            ??= \Components\Data\DataRegistry::config()->isConfigured($module);
    }

    /** Mark the module as configured. */
    public static function setConfigured(string $module): void
    {
        \Components\Data\DataRegistry::config()->setConfigured($module);
        self::$isConfiguredCache[$module] = true;
    }

    /** Clear the configured marker for the module (e.g., after uninstall). */
    public static function clearConfigured(string $module): void
    {
        \Components\Data\DataRegistry::config()->clearConfigured($module);
        self::$isConfiguredCache[$module] = false;
    }

    /** Get or create a private feed token for the calendar. */
    public static function getCalendarFeedToken(): string
    {
        return self::$calendarFeedTokenCache
            ??= \Components\Data\DataRegistry::config()->getCalendarFeedToken();
    }

    /** Generate a new private feed token for the calendar. */
    public static function rotateCalendarFeedToken(): string
    {
        $newToken = \Components\Data\DataRegistry::config()->rotateCalendarFeedToken();
        self::$calendarFeedTokenCache = $newToken;
        return $newToken;
    }

    /** Read the saved layout name for a logical list identifier. Defaults to 'stack'. */
    public static function getListLayout(string $listId): string
    {
        return self::$listLayoutCache[$listId]
            ??= \Components\Data\DataRegistry::config()->getListLayout($listId);
    }

    /** Persist the selected layout for the given list identifier (user-scoped). */
    public static function setListLayout(string $listId, string $layout): void
    {
        \Components\Data\DataRegistry::config()->setListLayout($listId, $layout);
        self::$listLayoutCache[$listId] = $layout;
    }

    /** Read the saved grouped flag for a logical list identifier. */
    public static function getListGrouped(string $listId, bool $default = true): bool
    {
        return self::$listGroupedCache[$listId]
            ??= \Components\Data\DataRegistry::config()->getListGrouped($listId, $default);
    }

    /** Persist the grouped flag for the given list identifier (user-scoped). */
    public static function setListGrouped(string $listId, bool $grouped): void
    {
        \Components\Data\DataRegistry::config()->setListGrouped($listId, $grouped);
        self::$listGroupedCache[$listId] = $grouped;
    }

    /** Read the saved per-page value for a logical list identifier. Defaults to $default. */
    public static function getListPerPage(string $listId, int $default = 25): int
    {
        return self::$listPerPageCache[$listId]
            ??= \Components\Data\DataRegistry::config()->getListPerPage($listId, $default);
    }

    /** Persist the per-page value for the given list identifier (user-scoped). */
    public static function setListPerPage(string $listId, int $perPage): void
    {
        \Components\Data\DataRegistry::config()->setListPerPage($listId, $perPage);
        self::$listPerPageCache[$listId] = $perPage;
    }

    /**
     * Read the full newsletter UI state blob for the current user.
     * Keys: sidebar_width, sidebar_collapsed, selected_slug, smart_layout, smart_hidden, sections_open.
     */
    public static function getNewsletterUiState(string $pageMode = ''): array
    {
        return self::$newsletterUiStateCache[$pageMode]
            ??= \Components\Data\DataRegistry::config()->getNewsletterUiState($pageMode);
    }

    /**
     * Merge and persist newsletter UI state fields for the current user.
     */
    public static function setNewsletterUiState(array $patch, string $pageMode = ''): void
    {
         \Components\Data\DataRegistry::config()->setNewsletterUiState($patch, $pageMode);
         unset(self::$newsletterUiStateCache[$pageMode]);
    }

    /** Read the saved view mode for a logical view identifier. Defaults to 'journey'. */
    public static function getViewMode(string $viewId, string $default = 'journey'): string
    {
        return self::$viewModeCache[$viewId]
            ??= \Components\Data\DataRegistry::config()->getViewMode($viewId, $default);
    }

    /** Persist the selected view mode for the given view identifier (user-scoped). */
    public static function setViewMode(string $viewId, string $mode): void
    {
        \Components\Data\DataRegistry::config()->setViewMode($viewId, $mode);
        self::$viewModeCache[$viewId] = $mode;
    }

    /** Read the saved performance timeframe for a logical view identifier. Defaults to '30days'. */
    public static function getPerformanceTimeframe(string $context, string $default = 'all'): string
    {
        return self::$performanceTimeframeCache[$context]
            ??= \Components\Data\DataRegistry::config()->getPerformanceTimeframe($context, $default);
    }

    /** Persist the selected performance timeframe for the given view identifier (user-scoped). */
    public static function setPerformanceTimeframe(string $context, string $timeframe): void
    {
        \Components\Data\DataRegistry::config()->setPerformanceTimeframe($context, $timeframe);
        self::$performanceTimeframeCache[$context] = $timeframe;
    }
}