<?php
namespace Components\Data\Live;

use Components\Data\Contracts\ConfigStoreProvider;

class LiveLegacyConfigStoreProvider implements ConfigStoreProvider
{
    /**
     * In a real implementation, these would proxy to the application backend (DB/API).
     * For now, keep a non-persistent in-memory map for the request lifetime to avoid JSON usage.
     */
    private static array $map = [];
    /** @var array<string,string>|null */
    private static ?array $statusKeyByModule = null;
    /** @var array<string,string|null> */
    private static array $resolvedStatusKeyCache = [];


    public function getAllConfigs(): array
    {
        $out = [];
        // Try to enumerate all known modules via ModuleLoader and read their current values from legacy
        try {
            $all = \Components\ModuleLoader::all();
            foreach ($all as $modKey => $_meta) {
                $out[$modKey] = $this->getModuleConfig((string)$modKey);
            }
        } catch (\Throwable $e) {
            // ignore; fallback to in-memory map
        }
        // Ensure any modules only present in the request-local map are included as well
        foreach (self::$map as $modKey => $vals) {
            if (!isset($out[$modKey])) {
                $out[$modKey] = is_array($vals) ? $vals : [];
            }
        }
        return $out;
    }

    public function getModuleConfig(string $module): array
    {
        $module = (string)$module;
        $out = [];

        // Try to resolve module-specific blueprints (including aliases) and enumerate merged fields
        $blueprintPath = '';
        try {
            // Use merged blueprints (main + alias modules)
            $paths = \Components\ModuleLoader::mergedBlueprintPaths($module);
            if (!is_array($paths) || empty($paths)) {
                $root = defined('BEEZUI_ROOT') ? BEEZUI_ROOT : dirname(__DIR__, 3);
                $blueprintPath = $root . '/blueprint.yaml';
                $engine = new \Components\Form\Engine($blueprintPath);
            } else {
                $engine = \Components\Form\Engine::fromBlueprints($paths);
            }
            $fields = $engine->getFields();

            foreach ($fields as $name => $def) {
                $val = '';
                if (function_exists('mh_cfg')) {
                    try { $val = mh_cfg((string)$name, ''); } catch (\Throwable $e) { $val = ''; }
                }
                $defType = strtolower((string)($def['type'] ?? ''));
                $vType = strtolower((string)($def['validate']['type'] ?? ''));
                if (in_array($defType, ['toggle','checkbox'], true) || $vType === 'boolean') {
                    // Map legacy 'True'/'False' and other truthy values to BeezUI 'on'|''
                    $out[$name] = ($val === 'True' || $val === true || $val === 1 || $val === '1' || $val === 'on' || $val === 'true') ? 'on' : '';
                } else {
                    // Keep raw string (arrays like order_status_multiple will be normalized by renderer)
                    $out[$name] = is_array($val) ? $val : (string)$val;
                }
            }
        } catch (\Throwable $e) {
            // ignore blueprint errors
        }

        // Overlay any request-local overrides captured in the in-memory map for this request
        if (isset(self::$map[$module]) && is_array(self::$map[$module])) {
            $out = array_merge($out, self::$map[$module]);
        }

        return $out;
    }

    /**
     * Form control parameters that must never be persisted to legacy configuration.
     * These are hidden inputs rendered by ResourceEditForm for routing/UI state.
     */
    private const CONTROL_PARAMS = [
        '__form_submit', '__mode',
        'return', 'drawer', 'autoclose', 'keys', 'fields',
        'event_prefix', 'event', 'event_suffix',
        'ui_event_id', 'panel_id',
        'module', 'partial', 'status_toggle',
    ];

    public function setModuleConfig(string $module, array $values, bool $processOnlyGivenFields = false): void
    {
        $module = (string)$module;
        // Strip form control parameters that should never be stored in legacy configuration
        $values = array_diff_key($values, array_flip(self::CONTROL_PARAMS));
        // Prepare blueprint fields map for lookup; avoid iterating all fields when not needed
        $fields = null;
        $boolFields = [];
        try {
            $paths = \Components\ModuleLoader::mergedBlueprintPaths($module);
            if (!is_array($paths) || empty($paths)) {
                $root = defined('BEEZUI_ROOT') ? BEEZUI_ROOT : dirname(__DIR__, 3);
                $blueprintPath = $root . '/blueprint.yaml';
                $engine = new \Components\Form\Engine($blueprintPath);
            } else {
                $engine = \Components\Form\Engine::fromBlueprints($paths);
            }
            $fields = $engine->getFields();
            // Build a fast lookup map of boolean fields
            if (is_array($fields)) {
                foreach ($fields as $fname => $def) {
                    $defType = strtolower((string)($def['type'] ?? ''));
                    $vType = strtolower((string)($def['validate']['type'] ?? ''));
                    if (in_array($defType, ['toggle','checkbox'], true) || $vType === 'boolean') {
                        $boolFields[(string)$fname] = true;
                    }
                }
            }
        } catch (\Throwable $e) {
            $fields = null; // fallback to key name heuristics
        }

        // Persist through legacy config where available
        $persistedAny = false;
        // Track which values we actually persisted (used for request-local overlay in partial mode)
        $overlaySubset = [];
        foreach ($values as $key => $val) {
            $cfgKey = (string)$key;
            if ($cfgKey === '') { continue; }
            // Normalize arrays to comma-separated string
            if (is_array($val)) {
                $norm = implode(',', array_map('strval', $val));
            } else {
                $norm = (string)$val;
            }
            // Decide if this key represents a boolean field
            $isBool = (isset($boolFields[$cfgKey]) && $boolFields[$cfgKey] === true) || preg_match('/(_STATUS|_ENABLED?|_ENABLE)$/', $cfgKey);
            // Coerce toggle semantics ONLY for boolean fields: 'on'|'true'|'1' => 'True', '' => 'False'
            if ($isBool) {
                if ($norm === 'on' || $norm === 'true' || $norm === 'True' || $norm === '1') {
                    $norm = 'True';
                } elseif ($norm === '') {
                    $norm = 'False';
                }
            }

            if ($this->persistLegacyConfig($cfgKey, $norm)) {
                $persistedAny = true;
            }


            // Collect overlay subset for partial updates (use UI-facing value as provided)
            if ($processOnlyGivenFields) {
                $overlaySubset[$cfgKey] = $val;
            }
        }
        // Maintain an in-memory overlay for this request so UI reflects immediately
        if (!isset(self::$map[$module]) || !is_array(self::$map[$module])) {
            self::$map[$module] = [];
        }
        if ($processOnlyGivenFields) {
            // Merge only the actually persisted subset onto the existing overlay
            if (!empty($overlaySubset)) {
                self::$map[$module] = array_merge(self::$map[$module], $overlaySubset);
            }
        } else {
            // Full save: replace overlay entirely with the provided values so UI reflects exact state
            self::$map[$module] = $values;
        }

    }

    public function getAllStatuses(): array
    {
        $out = [];
        try {
            $all = \Components\ModuleLoader::all();
            foreach ($all as $key => $meta) {
                $out[$key] = $this->isModuleOn($key) ? 'on' : '';
            }
        } catch (\Throwable $e) {
            // Fallback: derive from in-memory map using legacy *_STATUS convention
            foreach (self::$map 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
    {
        $statusKey = $this->resolveStatusKey($module);
        if (is_string($statusKey) && $statusKey !== '' && function_exists('mh_cfg')) {
            try {
                $val = mh_cfg($statusKey);
                // Legacy uses 'True'/'False' strings
                return $val === 'True' || $val === true || $val === 1 || $val === '1';
            } catch (\Throwable $e) {
                // ignore and fallback
            }
        }
//        // Fallback to in-memory map status flag
//        $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
    {
        $statusKey = $this->resolveStatusKey($module);
        if (is_string($statusKey) && $statusKey !== '') {
            $this->persistLegacyConfig($statusKey, $on ? 'True' : 'False');
        }
        // Also reflect the change in the in-memory map for UI consistency within this request
        if (!isset(self::$map[$module]) || !is_array(self::$map[$module])) {
            self::$map[$module] = [];
        }
        $keyForMap = $statusKey;
        if (!is_string($keyForMap) || $keyForMap === '') {
            // Fallback: try to discover status key from current config
            $current = $this->getModuleConfig($module);
            $keyForMap = $this->findStatusKey($current) ?? '_STATUS';
        }
        self::$map[$module][$keyForMap] = $on ? 'on' : '';
    }

    public function listKeys(string $module): array
    {
        // Derive from merged blueprints via Form Engine so modules can declare expected keys
        $blueprintPath = '';
        try {
            $paths = \Components\ModuleLoader::mergedBlueprintPaths($module);
            if (!is_array($paths) || empty($paths)) {
                $root = defined('BEEZUI_ROOT') ? BEEZUI_ROOT : dirname(__DIR__, 3);
                $blueprintPath = $root . '/blueprint.yaml';
                $engine = new \Components\Form\Engine($blueprintPath);
            } else {
                $engine = \Components\Form\Engine::fromBlueprints($paths);
            }
            return array_keys($engine->getFields());
        } catch (\Throwable $e) {
            return array_keys(self::$map[$module] ?? []);
        }
    }

    public function isConfigured(string $module): bool
    {
        // For legacy, we might check if a certain key exists, but standard is to use BeezUI state
        return false;
    }

    public function setConfigured(string $module): void
    {
        // No-op for legacy
    }

    public function clearConfigured(string $module): void
    {
        // No-op for legacy
    }

    // UI state methods are implemented by LiveBeezUIConfigStoreProvider;
    // these stubs satisfy the ConfigStoreProvider interface contract.

    public function getUiOpenMap(): array { return []; }
    public function setUiOpenState(string $module, bool $open): void {}
    public function getColumnStateMap(): array { return []; }
    public function setColumnState(string $key, bool $visible): void {}
    public function getDismissedNotifications(): array { return []; }
    public function setNotificationDismissed(string $id, bool $dismissed): void {}
    public function getListLayout(string $listId): string { return 'stack'; }
    public function setListLayout(string $listId, string $layout): void {}
    public function getListGrouped(string $listId, bool $default = true): bool { return (bool)$default; }
    public function setListGrouped(string $listId, bool $grouped): void {}

    public function getListPerPage(string $listId, int $default = 25): int { return $default; }

    public function setListPerPage(string $listId, int $perPage): void {}
    public function getNewsletterUiState(string $pageMode = ''): array { return []; }
    public function setNewsletterUiState(array $patch, string $pageMode = ''): void {}

    public function getViewMode(string $viewId, string $default = 'journey'): string { return $default; }
    public function setViewMode(string $viewId, string $mode): void {}

    public function getPerformanceTimeframe(string $context, string $default = '30days'): string { return $default; }
    public function setPerformanceTimeframe(string $context, string $timeframe): void {}

    public function getCalendarFeedToken(): string { return ''; }
    public function rotateCalendarFeedToken(): string { return ''; }

    private function resolveStatusKey(string $module): ?string
    {
        $module = trim((string)$module);
        if ($module === '') {
            return null;
        }

        if (array_key_exists($module, self::$resolvedStatusKeyCache)) {
            return self::$resolvedStatusKeyCache[$module];
        }

        if (self::$statusKeyByModule === null) {
            self::$statusKeyByModule = [];
            try {
                $all = \Components\ModuleLoader::all();
                foreach ($all as $modKey => $meta) {
                    $modKey = (string)$modKey;
                    if ($modKey === '') {
                        continue;
                    }
                    $statusKey = $meta['status_key'] ?? null;
                    if (is_string($statusKey) && $statusKey !== '') {
                        self::$statusKeyByModule[$modKey] = $statusKey;
                    }
                }
            } catch (\Throwable $e) {
                // ignore
            }
        }

        if (isset(self::$statusKeyByModule[$module])) {
            self::$resolvedStatusKeyCache[$module] = self::$statusKeyByModule[$module];
            return self::$resolvedStatusKeyCache[$module];
        }

        // Fallback: inspect in-memory config keys for *_STATUS
        $vals = $this->getModuleConfig($module);
        $found = $this->findStatusKey($vals);
        self::$resolvedStatusKeyCache[$module] = $found !== null ? $found : null;
        return self::$resolvedStatusKeyCache[$module];
    }

    private function findStatusKey(array $values): ?string
    {
        foreach ($values as $k => $_) {
            if (is_string($k) && preg_match('/_STATUS$/', $k)) {
                return $k;
            }
        }
        return null;
    }

    private function isOnValue($v): bool
    {
        return $v === 'on' || $v === '1' || $v === 1 || $v === true || $v === 'true';
    }

    /**
     * Persist a configuration value to legacy storage and refresh cache.
     *
     * @param string $key
     * @param string $value
     * @return bool
     */
    private function persistLegacyConfig(string $key, string $value): bool
    {
        $persisted = false;
        if (function_exists('mh_insert_or_update_config_value')) {
            try {
                mh_insert_or_update_config_value($key, $value);
                $persisted = true;
            } catch (\Throwable $e) { /* ignore */ }
        }

        if (!$persisted && function_exists('mh_update_config_value')) {
            try {
                mh_update_config_value([
                    'configuration_key'   => $key,
                    'configuration_value' => $value,
                ]);
                $persisted = true;
            } catch (\Throwable $e) { /* ignore */ }
        }

        if ($persisted) {
            if (function_exists('mh_cfg_override_set')) {
                try { mh_cfg_override_set($key, $value); } catch (\Throwable $e) { /* ignore */ }
            } elseif (function_exists('mh_cfg_refresh')) {
                try { mh_cfg_refresh($key); } catch (\Throwable $e) { /* ignore */ }
            }
        }

        return $persisted;
    }

}
