<?php
/*******************************************************************************************************************
| Software Name        : EasyStream
| Software Description : High End YouTube Clone Script with Videos, Shorts, Streams, Images, Audio, Documents, Blogs
| Software Author      : (c) Sami Ahmed
|*******************************************************************************************************************
|
|*******************************************************************************************************************
| This source file is subject to the EasyStream Proprietary License Agreement.
|
| By using this software, you acknowledge having read this Agreement and agree to be bound thereby.
|*******************************************************************************************************************
| Copyright (c) 2025 Sami Ahmed. All rights reserved.
|*******************************************************************************************************************/

defined('_ISVALID') or header('Location: /error');

/**
 * Settings Management Class
 * Provides unified interface for all system settings stored in db_settings table
 */
class Settings
{
    private $pdo;
    private $redis;
    private $cache = [];
    private $cacheLoaded = false;
    private $redisKey = 'easystream:settings:all';
    private $redisTTL = 3600; // 1 hour cache

    // Sensitive settings that should be encrypted
    private $encryptedKeys = [
        'paypal_secret',
        'paypal_client_id',
        'stripe_secret_key',
        'stripe_webhook_secret',
        'mail_smtp_password',
        'google_client_secret',
        'fb_app_secret',
        'twitter_api_secret',
    ];

    // Validation rules for settings
    private $validationRules = [
        // Email settings
        'backend_email' => ['type' => 'email', 'required' => true, 'label' => 'Admin Email'],
        'mail_smtp_username' => ['type' => 'email', 'required' => false, 'label' => 'SMTP Username'],
        'paypal_email' => ['type' => 'email', 'required' => false, 'label' => 'PayPal Email'],

        // URL settings
        'branding_logo_url' => ['type' => 'url', 'required' => false, 'label' => 'Logo URL'],
        'branding_favicon_url' => ['type' => 'url', 'required' => false, 'label' => 'Favicon URL'],
        'main_url' => ['type' => 'url', 'required' => true, 'label' => 'Main URL'],

        // Color settings
        'branding_primary_color' => ['type' => 'color', 'pattern' => '/^#[0-9A-F]{6}$/i', 'required' => true, 'label' => 'Primary Color'],
        'branding_secondary_color' => ['type' => 'color', 'pattern' => '/^#[0-9A-F]{6}$/i', 'required' => true, 'label' => 'Secondary Color'],
        'token_color' => ['type' => 'color', 'pattern' => '/^#[0-9A-F]{6}$/i', 'required' => false, 'label' => 'Token Color'],

        // Integer settings
        'mail_smtp_port' => ['type' => 'int', 'min' => 1, 'max' => 65535, 'required' => true, 'label' => 'SMTP Port'],
        'creator_payout_percentage' => ['type' => 'int', 'min' => 0, 'max' => 100, 'required' => true, 'label' => 'Payout Percentage'],
        'signup_min_age' => ['type' => 'int', 'min' => 13, 'max' => 100, 'required' => true, 'label' => 'Minimum Age'],
        'signup_max_age' => ['type' => 'int', 'min' => 13, 'max' => 150, 'required' => true, 'label' => 'Maximum Age'],
        'signup_min_password' => ['type' => 'int', 'min' => 4, 'max' => 50, 'required' => true, 'label' => 'Min Password Length'],
        'signup_max_password' => ['type' => 'int', 'min' => 8, 'max' => 100, 'required' => true, 'label' => 'Max Password Length'],
        'signup_min_username' => ['type' => 'int', 'min' => 3, 'max' => 20, 'required' => true, 'label' => 'Min Username Length'],
        'signup_max_username' => ['type' => 'int', 'min' => 5, 'max' => 50, 'required' => true, 'label' => 'Max Username Length'],

        // Float settings
        'minimum_payout_amount' => ['type' => 'float', 'min' => 0, 'required' => true, 'label' => 'Minimum Payout'],

        // Boolean settings
        'video_module' => ['type' => 'bool', 'label' => 'Video Module'],
        'live_module' => ['type' => 'bool', 'label' => 'Live Module'],
        'short_module' => ['type' => 'bool', 'label' => 'Short Module'],
        'image_module' => ['type' => 'bool', 'label' => 'Image Module'],
        'audio_module' => ['type' => 'bool', 'label' => 'Audio Module'],
        'document_module' => ['type' => 'bool', 'label' => 'Document Module'],
        'blog_module' => ['type' => 'bool', 'label' => 'Blog Module'],
        'stripe_enabled' => ['type' => 'bool', 'label' => 'Stripe Enabled'],
        'paypal_test' => ['type' => 'bool', 'label' => 'PayPal Test Mode'],
        'creator_payout_enabled' => ['type' => 'bool', 'label' => 'Creator Payouts Enabled'],
        'login_remember' => ['type' => 'bool', 'label' => 'Remember Me Feature'],
        'mail_smtp_auth' => ['type' => 'bool_string', 'label' => 'SMTP Authentication'],

        // String with pattern
        'stripe_publishable_key' => ['type' => 'string', 'pattern' => '/^pk_(test|live)_/', 'required' => false, 'label' => 'Stripe Publishable Key'],
        'stripe_secret_key' => ['type' => 'string', 'pattern' => '/^sk_(test|live)_/', 'required' => false, 'label' => 'Stripe Secret Key'],

        // String with length
        'website_shortname' => ['type' => 'string', 'min_length' => 1, 'max_length' => 50, 'required' => true, 'label' => 'Website Name'],
        'head_title' => ['type' => 'string', 'min_length' => 1, 'max_length' => 100, 'required' => true, 'label' => 'Site Title'],
        'backend_email_fromname' => ['type' => 'string', 'min_length' => 1, 'max_length' => 50, 'required' => true, 'label' => 'Email From Name'],
    ];

    /**
     * Initialize settings manager
     * @param PDO $pdo Database connection
     */
    public function __construct($pdo = null)
    {
        if ($pdo) {
            $this->pdo = $pdo;
        } else {
            // Use global PDO if available
            global $db_pdo;
            $this->pdo = $db_pdo ?? null;
        }

        // Initialize Redis if available
        try {
            if (class_exists('VRedis')) {
                $this->redis = VRedis::getInstance();
            }
        } catch (Exception $e) {
            $this->redis = null;
            error_log("Settings: Redis not available - " . $e->getMessage());
        }
    }

    /**
     * Load all settings into cache
     * @return bool Success status
     */
    private function loadCache()
    {
        if ($this->cacheLoaded) {
            return true;
        }

        // Try Redis first
        if ($this->redis) {
            try {
                $cached = $this->redis->get($this->redisKey);
                if ($cached) {
                    $this->cache = json_decode($cached, true);
                    $this->cacheLoaded = true;
                    return true;
                }
            } catch (Exception $e) {
                error_log("Settings: Redis cache read error - " . $e->getMessage());
            }
        }

        // Fallback to database
        if (!$this->pdo) {
            return false;
        }

        try {
            $stmt = $this->pdo->query("SELECT cfg_name, cfg_data, cfg_info FROM db_settings");
            while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                $this->cache[$row['cfg_name']] = [
                    'value' => $row['cfg_data'],
                    'info' => $row['cfg_info']
                ];
            }
            $this->cacheLoaded = true;

            // Store in Redis for next time
            if ($this->redis) {
                try {
                    $this->redis->set(
                        $this->redisKey,
                        json_encode($this->cache),
                        $this->redisTTL
                    );
                } catch (Exception $e) {
                    error_log("Settings: Redis cache write error - " . $e->getMessage());
                }
            }

            return true;
        } catch (PDOException $e) {
            error_log("Settings cache load error: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Get a setting value
     * @param string $key Setting name
     * @param mixed $default Default value if not found
     * @return mixed Setting value or default
     */
    public function get($key, $default = null)
    {
        $this->loadCache();

        if (isset($this->cache[$key])) {
            $value = $this->cache[$key]['value'];

            // Decrypt if needed
            if ($this->shouldEncrypt($key)) {
                return $this->decrypt($value);
            }

            return $value;
        }

        return $default;
    }

    /**
     * Get multiple settings at once
     * @param array $keys Array of setting names
     * @return array Associative array of settings
     */
    public function getMultiple(array $keys)
    {
        $this->loadCache();
        $results = [];

        foreach ($keys as $key) {
            $results[$key] = $this->get($key);
        }

        return $results;
    }

    /**
     * Get all settings in a category
     * @param string $prefix Category prefix (e.g., 'backend_', 'mail_', 'token_')
     * @return array Associative array of settings
     */
    public function getByPrefix($prefix)
    {
        $this->loadCache();
        $results = [];

        foreach ($this->cache as $key => $data) {
            if (strpos($key, $prefix) === 0) {
                $results[$key] = $data['value'];
            }
        }

        return $results;
    }

    /**
     * Check if a setting should be encrypted
     * @param string $key Setting name
     * @return bool
     */
    private function shouldEncrypt($key)
    {
        return in_array($key, $this->encryptedKeys);
    }

    /**
     * Get encryption key from config
     * @return string
     */
    private function getEncryptionKey()
    {
        return defined('ENC_FIRSTKEY') ? base64_decode(ENC_FIRSTKEY) : '';
    }

    /**
     * Get IV for encryption
     * @return string
     */
    private function getIV()
    {
        return defined('ENC_SECONDKEY') ? substr(base64_decode(ENC_SECONDKEY), 0, 16) : '';
    }

    /**
     * Encrypt a value
     * @param string $value Value to encrypt
     * @return string Encrypted value
     */
    private function encrypt($value)
    {
        if (empty($value)) {
            return $value;
        }

        try {
            $encrypted = openssl_encrypt(
                $value,
                'AES-256-CBC',
                $this->getEncryptionKey(),
                0,
                $this->getIV()
            );
            return base64_encode($encrypted);
        } catch (Exception $e) {
            error_log("Settings encryption error: " . $e->getMessage());
            return $value;
        }
    }

    /**
     * Decrypt a value
     * @param string $value Value to decrypt
     * @return string Decrypted value
     */
    private function decrypt($value)
    {
        if (empty($value)) {
            return $value;
        }

        try {
            $decrypted = openssl_decrypt(
                base64_decode($value),
                'AES-256-CBC',
                $this->getEncryptionKey(),
                0,
                $this->getIV()
            );
            return $decrypted ?: $value;
        } catch (Exception $e) {
            error_log("Settings decryption error: " . $e->getMessage());
            return $value;
        }
    }

    /**
     * Validate a setting value
     * @param string $key Setting name
     * @param mixed $value Value to validate
     * @return array ['valid' => bool, 'error' => string]
     */
    public function validate($key, $value)
    {
        // No rules = allow
        if (!isset($this->validationRules[$key])) {
            return ['valid' => true];
        }

        $rule = $this->validationRules[$key];

        // Check required
        if (isset($rule['required']) && $rule['required'] && ($value === '' || $value === null)) {
            return [
                'valid' => false,
                'error' => "{$rule['label']} is required"
            ];
        }

        // Skip validation if empty and not required
        if (($value === '' || $value === null) && (!isset($rule['required']) || !$rule['required'])) {
            return ['valid' => true];
        }

        // Type-specific validation
        switch ($rule['type']) {
            case 'email':
                if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be a valid email address"];
                }
                break;

            case 'url':
                if (!filter_var($value, FILTER_VALIDATE_URL)) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be a valid URL"];
                }
                break;

            case 'color':
                if (isset($rule['pattern']) && !preg_match($rule['pattern'], $value)) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be a valid hex color (e.g., #FF0000)"];
                }
                break;

            case 'int':
                if (!is_numeric($value) || (int)$value != $value) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be a whole number"];
                }
                $intVal = (int)$value;
                if (isset($rule['min']) && $intVal < $rule['min']) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be at least {$rule['min']}"];
                }
                if (isset($rule['max']) && $intVal > $rule['max']) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be at most {$rule['max']}"];
                }
                break;

            case 'float':
                if (!is_numeric($value)) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be a number"];
                }
                $floatVal = (float)$value;
                if (isset($rule['min']) && $floatVal < $rule['min']) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be at least {$rule['min']}"];
                }
                if (isset($rule['max']) && $floatVal > $rule['max']) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be at most {$rule['max']}"];
                }
                break;

            case 'bool':
                if (!in_array($value, ['0', '1', 0, 1, true, false], true)) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be 0 or 1"];
                }
                break;

            case 'bool_string':
                if (!in_array($value, ['true', 'false'], true)) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be 'true' or 'false'"];
                }
                break;

            case 'string':
                if (isset($rule['min_length']) && strlen($value) < $rule['min_length']) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be at least {$rule['min_length']} characters"];
                }
                if (isset($rule['max_length']) && strlen($value) > $rule['max_length']) {
                    return ['valid' => false, 'error' => "{$rule['label']} must be at most {$rule['max_length']} characters"];
                }
                if (isset($rule['pattern']) && !preg_match($rule['pattern'], $value)) {
                    return ['valid' => false, 'error' => "{$rule['label']} has an invalid format"];
                }
                break;
        }

        return ['valid' => true];
    }

    /**
     * Set a setting value
     * @param string $key Setting name
     * @param mixed $value Setting value
     * @param string $info Optional description
     * @return bool Success status
     */
    public function set($key, $value, $info = '')
    {
        if (!$this->pdo) {
            return false;
        }

        // Validate before saving
        $validation = $this->validate($key, $value);
        if (!$validation['valid']) {
            throw new InvalidArgumentException($validation['error']);
        }

        try {
            // Get old value for audit trail
            $oldValue = $this->get($key);

            // Encrypt sensitive values before saving
            $saveValue = $this->shouldEncrypt($key) ? $this->encrypt($value) : $value;

            // Check if setting exists
            $stmt = $this->pdo->prepare("SELECT id FROM db_settings WHERE cfg_name = ?");
            $stmt->execute([$key]);
            $exists = $stmt->fetch();

            if ($exists) {
                // Update existing setting
                $stmt = $this->pdo->prepare("UPDATE db_settings SET cfg_data = ?, cfg_info = ? WHERE cfg_name = ?");
                $result = $stmt->execute([$saveValue, $info ?: $this->cache[$key]['info'] ?? '', $key]);
            } else {
                // Insert new setting
                $stmt = $this->pdo->prepare("INSERT INTO db_settings (cfg_name, cfg_data, cfg_info) VALUES (?, ?, ?)");
                $result = $stmt->execute([$key, $saveValue, $info]);
            }

            // Update cache
            $this->cache[$key] = [
                'value' => $value,
                'info' => $info ?: ($this->cache[$key]['info'] ?? '')
            ];

            // Log the change to audit trail
            $this->logChange($key, $oldValue, $value);

            // Invalidate Redis cache
            if ($this->redis) {
                try {
                    $this->redis->delete($this->redisKey);
                } catch (Exception $e) {
                    error_log("Settings: Redis cache invalidation error - " . $e->getMessage());
                }
            }

            return $result;
        } catch (PDOException $e) {
            error_log("Settings set error: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Set multiple settings at once
     * @param array $settings Associative array of key => value pairs
     * @return bool Success status
     */
    public function setMultiple(array $settings)
    {
        if (!$this->pdo) {
            return false;
        }

        try {
            $this->pdo->beginTransaction();

            foreach ($settings as $key => $value) {
                $this->set($key, $value);
            }

            $this->pdo->commit();
            return true;
        } catch (Exception $e) {
            $this->pdo->rollBack();
            error_log("Settings setMultiple error: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Delete a setting
     * @param string $key Setting name
     * @return bool Success status
     */
    public function delete($key)
    {
        if (!$this->pdo) {
            return false;
        }

        try {
            $stmt = $this->pdo->prepare("DELETE FROM db_settings WHERE cfg_name = ?");
            $result = $stmt->execute([$key]);

            unset($this->cache[$key]);

            return $result;
        } catch (PDOException $e) {
            error_log("Settings delete error: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Get all settings grouped by category
     * @return array Multi-dimensional array of settings by category
     */
    public function getAllGrouped()
    {
        $this->loadCache();

        $grouped = [
            'general' => [],
            'backend' => [],
            'frontend' => [],
            'mail' => [],
            'payment' => [],
            'token' => [],
            'branding' => [],
            'security' => [],
            'seo' => [],
            'modules' => [],
            'conversion' => [],
            'social' => [],
            'other' => []
        ];

        foreach ($this->cache as $key => $data) {
            $category = 'other';

            if (strpos($key, 'backend_') === 0) {
                $category = 'backend';
            } elseif (strpos($key, 'mail_') === 0) {
                $category = 'mail';
            } elseif (strpos($key, 'paypal_') === 0 || strpos($key, 'stripe_') === 0 || strpos($key, 'payment_') === 0) {
                $category = 'payment';
            } elseif (strpos($key, 'token_') === 0) {
                $category = 'token';
            } elseif (strpos($key, 'branding_') === 0 || strpos($key, 'color_') === 0 || strpos($key, 'logo_') === 0) {
                $category = 'branding';
            } elseif (strpos($key, 'signup_') === 0 || strpos($key, 'login_') === 0 || strpos($key, 'username_') === 0) {
                $category = 'security';
            } elseif (strpos($key, 'head_') === 0 || strpos($key, 'metaname_') === 0 || strpos($key, 'website_') === 0) {
                $category = 'seo';
            } elseif (strpos($key, '_module') !== false || $key === 'paid_memberships') {
                $category = 'modules';
            } elseif (strpos($key, 'conversion_') === 0) {
                $category = 'conversion';
            } elseif (strpos($key, 'fb_') === 0 || strpos($key, 'google_') === 0 || strpos($key, 'twitter_') === 0) {
                $category = 'social';
            } else {
                $category = 'general';
            }

            $grouped[$category][$key] = [
                'value' => $data['value'],
                'info' => $data['info']
            ];
        }

        return $grouped;
    }

    /**
     * Export all settings as JSON
     * @return string JSON string
     */
    public function exportJSON()
    {
        $this->loadCache();
        return json_encode($this->cache, JSON_PRETTY_PRINT);
    }

    /**
     * Import settings from JSON
     * @param string $json JSON string
     * @return bool Success status
     */
    public function importJSON($json)
    {
        $data = json_decode($json, true);

        if (!$data) {
            return false;
        }

        try {
            $this->pdo->beginTransaction();

            foreach ($data as $key => $item) {
                $this->set($key, $item['value'], $item['info'] ?? '');
            }

            $this->pdo->commit();
            return true;
        } catch (Exception $e) {
            $this->pdo->rollBack();
            error_log("Settings import error: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Check if a module is enabled
     * @param string $module Module name (video, live, blog, etc.)
     * @return bool Enabled status
     */
    public function isModuleEnabled($module)
    {
        return $this->get($module . '_module', '0') === '1';
    }

    /**
     * Enable or disable a module
     * @param string $module Module name
     * @param bool $enabled Enable/disable
     * @return bool Success status
     */
    public function setModuleEnabled($module, $enabled)
    {
        return $this->set($module . '_module', $enabled ? '1' : '0');
    }

    /**
     * Get site branding information
     * @return array Branding settings
     */
    public function getBranding()
    {
        return [
            'site_name' => $this->get('website_shortname', 'EasyStream'),
            'site_title' => $this->get('head_title', 'EasyStream'),
            'primary_color' => $this->get('branding_primary_color', '#1a73e8'),
            'secondary_color' => $this->get('branding_secondary_color', '#34a853'),
            'logo_url' => $this->get('branding_logo_url', ''),
            'favicon_url' => $this->get('branding_favicon_url', ''),
            'meta_description' => $this->get('metaname_description', ''),
            'meta_keywords' => $this->get('metaname_keywords', '')
        ];
    }

    /**
     * Get payment gateway configuration
     * @return array Payment settings
     */
    public function getPaymentConfig()
    {
        return [
            'enabled_gateways' => explode(',', $this->get('payment_methods', 'Paypal')),
            'paypal' => [
                'email' => $this->get('paypal_email', ''),
                'test_mode' => $this->get('paypal_test', '1') === '1',
                'client_id' => $this->get('paypal_client_id', ''),
                'secret' => $this->get('paypal_secret', '')
            ],
            'stripe' => [
                'enabled' => $this->get('stripe_enabled', '0') === '1',
                'publishable_key' => $this->get('stripe_publishable_key', ''),
                'secret_key' => $this->get('stripe_secret_key', ''),
                'webhook_secret' => $this->get('stripe_webhook_secret', '')
            ]
        ];
    }

    /**
     * Get email/SMTP configuration
     * @return array Email settings
     */
    public function getEmailConfig()
    {
        return [
            'type' => $this->get('mail_type', 'smtp'),
            'from_email' => $this->get('backend_email', ''),
            'from_name' => $this->get('backend_email_fromname', 'Webmaster'),
            'smtp' => [
                'host' => $this->get('mail_smtp_host', 'smtp.gmail.com'),
                'port' => (int)$this->get('mail_smtp_port', '587'),
                'username' => $this->get('mail_smtp_username', ''),
                'password' => $this->get('mail_smtp_password', ''),
                'auth' => $this->get('mail_smtp_auth', 'true') === 'true',
                'prefix' => $this->get('mail_smtp_prefix', 'tls')
            ]
        ];
    }

    /**
     * Get token economy configuration
     * @return array Token settings
     */
    public function getTokenConfig()
    {
        return [
            'enabled' => $this->get('token_system_enabled', '1') === '1',
            'name' => $this->get('token_name', 'Tokens'),
            'symbol' => $this->get('token_symbol', 'TKN'),
            'color' => $this->get('token_color', '#FFD700'),
            'icon_url' => $this->get('token_icon_url', ''),
            'creator_payout_enabled' => $this->get('creator_payout_enabled', '0') === '1',
            'creator_payout_percentage' => (int)$this->get('creator_payout_percentage', '70'),
            'minimum_payout' => (float)$this->get('minimum_payout_amount', '50.00')
        ];
    }

    /**
     * Log a settings change to audit trail
     * @param string $key Setting name
     * @param mixed $oldValue Old value
     * @param mixed $newValue New value
     * @param string $reason Change reason
     * @return bool Success status
     */
    private function logChange($key, $oldValue, $newValue, $reason = '')
    {
        if (!$this->pdo) {
            return false;
        }

        global $usr;

        try {
            $stmt = $this->pdo->prepare("
                INSERT INTO db_settings_history
                (cfg_name, old_value, new_value, changed_by, ip_address, user_agent, change_reason)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            ");

            return $stmt->execute([
                $key,
                $oldValue,
                $newValue,
                $usr['id'] ?? $_SESSION['admin_user_id'] ?? 0,
                $_SERVER['REMOTE_ADDR'] ?? '',
                substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 255),
                $reason
            ]);
        } catch (PDOException $e) {
            error_log("Settings audit log error: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Get change history for a specific setting
     * @param string $key Setting name
     * @param int $limit Number of records to return
     * @return array History records
     */
    public function getHistory($key, $limit = 20)
    {
        if (!$this->pdo) {
            return [];
        }

        try {
            $stmt = $this->pdo->prepare("
                SELECT h.*, u.usr_user as username
                FROM db_settings_history h
                LEFT JOIN db_accountuser u ON h.changed_by = u.usr_id
                WHERE h.cfg_name = ?
                ORDER BY h.changed_at DESC
                LIMIT ?
            ");
            $stmt->execute([$key, $limit]);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (PDOException $e) {
            error_log("Settings history error: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Get all recent settings changes
     * @param int $limit Number of records to return
     * @return array History records
     */
    public function getAllRecentChanges($limit = 50)
    {
        if (!$this->pdo) {
            return [];
        }

        try {
            $stmt = $this->pdo->prepare("
                SELECT h.*, u.usr_user as username, s.cfg_info
                FROM db_settings_history h
                LEFT JOIN db_accountuser u ON h.changed_by = u.usr_id
                LEFT JOIN db_settings s ON h.cfg_name = s.cfg_name
                ORDER BY h.changed_at DESC
                LIMIT ?
            ");
            $stmt->execute([$limit]);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (PDOException $e) {
            error_log("Settings recent changes error: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Rollback a setting to a previous value from history
     * @param string $key Setting name
     * @param int $historyId History record ID to rollback to
     * @return bool Success status
     */
    public function rollback($key, $historyId)
    {
        if (!$this->pdo) {
            return false;
        }

        try {
            // Get the historical value
            $stmt = $this->pdo->prepare("SELECT old_value FROM db_settings_history WHERE id = ? AND cfg_name = ?");
            $stmt->execute([$historyId, $key]);
            $history = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$history) {
                return false;
            }

            // Set the old value back
            return $this->set($key, $history['old_value'], '', 'Rollback from history #' . $historyId);
        } catch (PDOException $e) {
            error_log("Settings rollback error: " . $e->getMessage());
            return false;
        }
    }
}
