<?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 DISMISSED_KEY = 'dismissed_notifications';

    /** 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 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 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';
    }
}
