<?php
namespace Components\Data\Mock;

use Components\Data\Contracts\ConfigStoreProvider;

class MockConfigStoreProvider implements ConfigStoreProvider
{
    private const STORE_FILE = 'var/config_store.json';
    private const MODULE_CONFIG_KEY = 'module_config';
    private const UI_OPEN_KEY = 'ui_open_map';
    private const COLUMN_STATE_KEY = 'column_state_map';
    private const DISMISSED_KEY = 'dismissed_notifications';
    private const LIST_LAYOUT_KEY = 'list_layout_map';
    private const LIST_GROUPED_KEY = 'list_grouped_map';
    private const LIST_PER_PAGE_KEY = 'list_per_page_map';
    private const NEWSLETTER_UI_KEY = 'newsletter_ui_state';
    private const VIEW_MODE_KEY = 'view_mode_map';
    private const PERFORMANCE_TIMEFRAME_KEY = 'performance_timeframe_map';

    /** Resolve absolute path to store file and ensure directory exists */
    private static function storePath(): string
    {
        $root = defined('BEEZUI_ROOT') ? BEEZUI_ROOT : dirname(__DIR__, 3);
        $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);
    }

    public function getAllConfigs(): array
    {
        $store = self::readStore();
        $map = $store[self::MODULE_CONFIG_KEY] ?? [];
        return is_array($map) ? $map : [];
    }

    public function getModuleConfig(string $module): array
    {
        $module = (string)$module;
        $configs = $this->getAllConfigs();
        if (isset($configs[$module]) && is_array($configs[$module])) {
            return $configs[$module];
        }
        return [];
    }

    public function setModuleConfig(string $module, array $values, bool $processOnlyGivenFields = false): void
    {
        $module = (string)$module;
        $store = self::readStore();
        if (!isset($store[self::MODULE_CONFIG_KEY]) || !is_array($store[self::MODULE_CONFIG_KEY])) {
            $store[self::MODULE_CONFIG_KEY] = [];
        }
        $existing = isset($store[self::MODULE_CONFIG_KEY][$module]) && is_array($store[self::MODULE_CONFIG_KEY][$module]) ? $store[self::MODULE_CONFIG_KEY][$module] : [];
        $store[self::MODULE_CONFIG_KEY][$module] = $processOnlyGivenFields ? array_merge($existing, $values) : $values;
        self::writeStore($store);
    }

    public function getAllStatuses(): array
    {
        $all = $this->getAllConfigs();
        $out = [];
        foreach ($all as $module => $vals) {
            if (!is_array($vals)) { $out[$module] = ''; continue; }
            $statusKey = $this->findStatusKey($vals);
            if ($statusKey !== null) {
                $out[$module] = ($this->isOnValue($vals[$statusKey] ?? '')) ? 'on' : '';
            } else {
                $out[$module] = '';
            }
        }
        return $out;
    }

    public function isModuleOn(string $module): bool
    {
        $module = (string)$module;
        $vals = $this->getModuleConfig($module);
        if (!empty($vals)) {
            $statusKey = $this->findStatusKey($vals);
            if ($statusKey !== null) {
                return $this->isOnValue($vals[$statusKey] ?? '');
            }
        }
        return false;
    }

    public function setModuleStatus(string $module, bool $on): void
    {
        $module = (string)$module;
        $vals = $this->getModuleConfig($module);
        $statusKey = $this->findStatusKey($vals);
        if ($statusKey === null) {
            // Fallback: create a generic status field for new modules
            $statusKey = '_STATUS';
        }
        $this->setModuleConfig($module, [ $statusKey => ($on ? 'on' : '') ], true);
    }

    public function getUiOpenMap(): array
    {
        $store = self::readStore();
        $map = $store[self::UI_OPEN_KEY] ?? [];
        if (!is_array($map)) { $map = []; }
        // Normalize to bool map
        $out = [];
        foreach ($map as $key => $val) {
            if (is_string($key) && $key !== '' && ($val === true || $val === 1 || $val === '1' || $val === 'on')) {
                $out[$key] = true;
            }
        }
        return $out;
    }

    public function setUiOpenState(string $module, bool $open): void
    {
        $module = (string)$module;
        if ($module === '') return;
        $store = self::readStore();
        if (!isset($store[self::UI_OPEN_KEY]) || !is_array($store[self::UI_OPEN_KEY])) {
            $store[self::UI_OPEN_KEY] = [];
        }
        if ($open) {
            $store[self::UI_OPEN_KEY][$module] = true;
        } else {
            unset($store[self::UI_OPEN_KEY][$module]);
        }
        self::writeStore($store);
    }

    public function getColumnStateMap(): array
    {
        $store = self::readStore();
        $map = $store[self::COLUMN_STATE_KEY] ?? [];
        if (!is_array($map)) { $map = []; }
        // Normalize to bool map
        $out = [];
        foreach ($map as $key => $val) {
            if (is_string($key) && $key !== '' && ($val === true || $val === 1 || $val === '1' || $val === 'on')) {
                $out[$key] = true;
            }
        }
        return $out;
    }

    public function setColumnState(string $key, bool $visible): void
    {
        $key = (string)$key;
        if ($key === '') return;
        $store = self::readStore();
        if (!isset($store[self::COLUMN_STATE_KEY]) || !is_array($store[self::COLUMN_STATE_KEY])) {
            $store[self::COLUMN_STATE_KEY] = [];
        }
        if ($visible) {
            $store[self::COLUMN_STATE_KEY][$key] = true;
        } else {
            unset($store[self::COLUMN_STATE_KEY][$key]);
        }
        self::writeStore($store);
    }

    public function getDismissedNotifications(): array
    {
        $store = self::readStore();
        $map = $store[self::DISMISSED_KEY] ?? [];
        if (!is_array($map)) { $map = []; }
        $out = [];
        foreach ($map as $key => $val) {
            if (is_string($key) && $key !== '' && ($val === true || $val === 1 || $val === '1' || $val === 'on')) {
                $out[$key] = true;
            }
        }
        return $out;
    }

    public function setNotificationDismissed(string $id, bool $dismissed): void
    {
        $id = (string)$id;
        if ($id === '') return;
        $store = self::readStore();
        if (!isset($store[self::DISMISSED_KEY]) || !is_array($store[self::DISMISSED_KEY])) {
            $store[self::DISMISSED_KEY] = [];
        }
        if ($dismissed) {
            $store[self::DISMISSED_KEY][$id] = true;
        } else {
            unset($store[self::DISMISSED_KEY][$id]);
        }
        self::writeStore($store);
    }

    public function getListLayout(string $listId): string
    {
        $store = self::readStore();
        $map = $store[self::LIST_LAYOUT_KEY] ?? [];
        return isset($map[$listId]) ? (string)$map[$listId] : 'stack';
    }

    public function setListLayout(string $listId, string $layout): void
    {
        $listId = (string)$listId;
        if ($listId === '') return;
        $store = self::readStore();
        if (!isset($store[self::LIST_LAYOUT_KEY]) || !is_array($store[self::LIST_LAYOUT_KEY])) {
            $store[self::LIST_LAYOUT_KEY] = [];
        }
        $store[self::LIST_LAYOUT_KEY][$listId] = $layout;
        self::writeStore($store);
    }

    public function getListGrouped(string $listId, bool $default = true): bool
    {
        $store = self::readStore();
        $map = $store[self::LIST_GROUPED_KEY] ?? [];
        if (!array_key_exists($listId, $map)) {
            return (bool)$default;
        }
        return (bool)$map[$listId];
    }

    public function setListGrouped(string $listId, bool $grouped): void
    {
        $listId = (string)$listId;
        if ($listId === '') return;
        $store = self::readStore();
        if (!isset($store[self::LIST_GROUPED_KEY]) || !is_array($store[self::LIST_GROUPED_KEY])) {
            $store[self::LIST_GROUPED_KEY] = [];
        }
        $store[self::LIST_GROUPED_KEY][$listId] = (bool)$grouped;
        self::writeStore($store);
    }

    public function getListPerPage(string $listId, int $default = 25): int
    {
        $store = self::readStore();
        $map = $store[self::LIST_PER_PAGE_KEY] ?? [];
        return isset($map[$listId]) ? (int)$map[$listId] : (int)$default;
    }

    public function setListPerPage(string $listId, int $perPage): void
    {
        $listId = (string)$listId;
        if ($listId === '') return;
        $store = self::readStore();
        if (!isset($store[self::LIST_PER_PAGE_KEY]) || !is_array($store[self::LIST_PER_PAGE_KEY])) {
            $store[self::LIST_PER_PAGE_KEY] = [];
        }
        $store[self::LIST_PER_PAGE_KEY][$listId] = (int)$perPage;
        self::writeStore($store);
    }

    public function getNewsletterUiState(string $pageMode = ''): array
    {
        if ($pageMode === '') {
            $pageMode = isset(\Components\Newsletter\PageConfig::fromRequest()->mode) ? \Components\Newsletter\PageConfig::fromRequest()->mode : 'newsletter';
        }
        $store = self::readStore();
        $key = self::NEWSLETTER_UI_KEY . '_' . strtoupper($pageMode);
        $state = $store[$key] ?? [];
        return is_array($state) ? $state : [];
    }

    public function setNewsletterUiState(array $patch, string $pageMode = ''): void
    {
        if ($pageMode === '') {
            $pageMode = isset(\Components\Newsletter\PageConfig::fromRequest()->mode) ? \Components\Newsletter\PageConfig::fromRequest()->mode : 'newsletter';
        }
        $store = self::readStore();
        $key = self::NEWSLETTER_UI_KEY . '_' . strtoupper($pageMode);
        $existing = $store[$key] ?? [];
        if (!is_array($existing)) { $existing = []; }
        $store[$key] = array_merge($existing, $patch);
        self::writeStore($store);
    }

    public function getViewMode(string $viewId, string $default = 'journey'): string
    {
        $store = self::readStore();
        $map = $store[self::VIEW_MODE_KEY] ?? [];
        return isset($map[$viewId]) ? (string)$map[$viewId] : (string)$default;
    }

    public function setViewMode(string $viewId, string $mode): void
    {
        $viewId = (string)$viewId;
        if ($viewId === '') return;
        $store = self::readStore();
        if (!isset($store[self::VIEW_MODE_KEY]) || !is_array($store[self::VIEW_MODE_KEY])) {
            $store[self::VIEW_MODE_KEY] = [];
        }
        $store[self::VIEW_MODE_KEY][$viewId] = $mode;
        self::writeStore($store);
    }

    public function getPerformanceTimeframe(string $context, string $default = '30days'): string
    {
        $store = self::readStore();
        $map = $store[self::PERFORMANCE_TIMEFRAME_KEY] ?? [];
        return isset($map[$context]) ? (string)$map[$context] : (string)$default;
    }

    public function setPerformanceTimeframe(string $context, string $timeframe): void
    {
        $context = (string)$context;
        if ($context === '') return;
        $store = self::readStore();
        if (!isset($store[self::PERFORMANCE_TIMEFRAME_KEY]) || !is_array($store[self::PERFORMANCE_TIMEFRAME_KEY])) {
            $store[self::PERFORMANCE_TIMEFRAME_KEY] = [];
        }
        $store[self::PERFORMANCE_TIMEFRAME_KEY][$context] = $timeframe;
        self::writeStore($store);
    }

    public function getCalendarFeedToken(): string
    {
        $store = self::readStore();
        if (!isset($store['calendar_feed_token'])) {
            return $this->rotateCalendarFeedToken();
        }
        return (string)$store['calendar_feed_token'];
    }

    public function rotateCalendarFeedToken(): string
    {
        $store = self::readStore();
        $token = bin2hex(random_bytes(16));
        $store['calendar_feed_token'] = $token;
        self::writeStore($store);
        return $token;
    }

    public function listKeys(string $module): array
    {
        // In mock mode, infer from the saved config keys; empty means no prior save
        $vals = $this->getModuleConfig($module);
        return array_keys($vals);
    }

    public function isConfigured(string $module): bool
    {
        $store = self::readStore();
        return isset($store['configured'][$module]);
    }

    public function setConfigured(string $module): void
    {
        $store = self::readStore();
        if (!isset($store['configured']) || !is_array($store['configured'])) {
            $store['configured'] = [];
        }
        $store['configured'][$module] = time();
        self::writeStore($store);
    }

    public function clearConfigured(string $module): void
    {
        $store = self::readStore();
        if (isset($store['configured']) && is_array($store['configured'])) {
            unset($store['configured'][$module]);
            self::writeStore($store);
        }
    }


    /** Find the status field key in a module's config. Convention: any key ending with "_STATUS". */
    private function findStatusKey(array $values): ?string
    {
        foreach ($values as $k => $_) {
            if (is_string($k) && preg_match('/_STATUS$/', $k)) {
                return $k;
            }
        }
        return null;
    }

    /** Normalize various truthy forms to boolean for status fields */
    private function isOnValue($v): bool
    {
        return $v === 'on' || $v === '1' || $v === 1 || $v === true || $v === 'true';
    }
}
