<?php
/**
 * Configuration Loader
 *
 * Loads and merges default configuration from separate config files.
 * This improves maintainability by splitting the massive options array into logical modules.
 *
 * @package UltimateSecurity
 * @since 2.0.0
 */

namespace WPUltimateSecurity\UltimateSecurity\Config;

use WPUltimateSecurity\UltimateSecurity\Support\Helpers\Utils;
class ConfigLoader
{
    /**
     * Config directory path
     *
     * @var string
     */
    private static string $configDir;

    /**
     * Cached config array
     *
     * @var array|null
     */
    private static ?array $cachedConfig = null;

    /**
     * Get the config directory path
     *
     * @return string
     */
    private static function getConfigDir(): string
    {
        if (!isset(self::$configDir)) {
            // Use the current directory to build a case‑correct, portable path.
            // On case‑sensitive filesystems (Linux) using "config" instead of "Config"
            // would point to a non‑existent directory and result in empty defaults.
            self::$configDir = __DIR__ . '/defaults/';
        }
        return self::$configDir;
    }

    /**
     * Load all default options from config files
     *
     * @return array Combined default options
     */
    public static function loadDefaults(): array
    {
        // Return cached config if available
        if (self::$cachedConfig !== null) {
            return self::$cachedConfig;
        }

        $configDir = self::getConfigDir();

        // Load each config file
        $authentication = self::loadConfigFile($configDir . 'authentication.php');
        $protection = self::loadConfigFile($configDir . 'protection.php');
        $hardening = self::loadConfigFile($configDir . 'hardening.php');
        $monitoring = self::loadConfigFile($configDir . 'monitoring.php');
        $maintenance = self::loadConfigFile($configDir . 'maintenance.php');

        // Build the combined config structure
        // REMOVED: restrictions - server-level features
        $config = [
            'security' => array_merge(
                $authentication,
                $protection,
                [
                    'salt_change' => $hardening['salt_change'] ?? [],
                    'api_privacy' => $hardening['api_privacy'] ?? [],
                    'recommendations' => $hardening['recommendations'] ?? [],
                    'comments' => $hardening['comments'] ?? [],
                    'email_notification' => $monitoring['email_notification'] ?? [],
                    'updates' => $maintenance['updates'] ?? [],
                ]
            ),

            'login' => $maintenance['login'] ?? [],
            'more' => $maintenance['more'] ?? [],
            'test_mode' => $monitoring['test_mode'] ?? [],
            'self_defense' => $hardening['self_defense'] ?? [],
            'audit_logs' => $monitoring['audit_logs'] ?? [],
            'audit_files' => $monitoring['audit_files'] ?? [],
            'rate_limiter' => $protection['rate_limiter'] ?? [],
            'compatibility' => $maintenance['compatibility'] ?? [],
            'security_headers' => $hardening['security_headers'] ?? [],
            'vulnerability_scanner' => $monitoring['vulnerability_scanner'] ?? [],
            'magic_link' => $authentication['magic_link'] ?? [],
            'security_level' => '',
        ];

        // Apply runtime defaults
        $config = self::applyRuntimeDefaults($config);

        // Cache the result
        self::$cachedConfig = $config;

        return $config;
    }

    /**
     * Load a single config file
     *
     * @param string $path Path to config file
     * @return array Config array or empty array if file doesn't exist
     */
    private static function loadConfigFile(string $path): array
    {
        if (!file_exists($path)) {
            return [];
        }

        $config = include $path;

        return is_array($config) ? $config : [];
    }

    /**
     * Apply runtime defaults (values that depend on WordPress state)
     *
     * @param array $config Config array
     * @return array Config with runtime defaults applied
     */
    private static function applyRuntimeDefaults(array $config): array
    {
        $adminEmail = function_exists('get_option') ? get_option('admin_email') : '';

        // Set email addresses that default to admin email
        if (empty($config['security']['email_notification']['notification_email'])) {
            $config['security']['email_notification']['notification_email'] = $adminEmail;
        }

        if (empty($config['vulnerability_scanner']['notification_email'])) {
            $config['vulnerability_scanner']['notification_email'] = $adminEmail;
        }

        // Set database cleanup retention policies if not set
        if (empty($config['more']['database_cleanup']['retention_policies'])) {
            $tables = Utils::ultimate_security_get_tables();
            $config['more']['database_cleanup']['retention_policies'] = array_fill_keys($tables, 90);
        }

        return $config;
    }

    /**
     * Clear the cached config
     *
     * Useful after config files have been modified.
     *
     * @return void
     */
    public static function clearCache(): void
    {
        self::$cachedConfig = null;
    }

    /**
     * Get a specific config section
     *
     * @param string $section Dot-notation path (e.g., 'security.2fa_authentication')
     * @return mixed Config value or null if not found
     */
    public static function get(string $section): mixed
    {
        $config = self::loadDefaults();
        $keys = explode('.', $section);

        foreach ($keys as $key) {
            if (!is_array($config) || !isset($config[$key])) {
                return null;
            }
            $config = $config[$key];
        }

        return $config;
    }
}
