<?php

declare(strict_types=1);

namespace ShieldX\Maintenance;

defined('ABSPATH') || exit;

use ShieldX\Core\RequestCache;

final class RestorePointSettings
{
    public const OPTION_NAME = 'shieldx_restore_point_settings';

    /** @var array<string,mixed> */
    private $settings;

    /**
     * @param array<string,mixed> $settings
     */
    public function __construct(array $settings = [])
    {
        $this->settings = self::normalize($settings);
    }

    public static function fromWordPress(): self
    {
        $cached = RequestCache::get(self::class);
        if ($cached instanceof self) {
            return $cached;
        }

        $saved = function_exists('get_option') ? get_option(self::OPTION_NAME, []) : [];

        $instance = new self(is_array($saved) ? $saved : []);
        RequestCache::rememberOption(self::class, self::OPTION_NAME, $instance);

        return $instance;
    }

    /**
     * @return array<string,mixed>
     */
    public function all(): array
    {
        return $this->settings;
    }

    /**
     * @param array<string,mixed> $settings
     */
    public function save(array $settings): void
    {
        $this->settings = self::normalize($settings);

        if (function_exists('update_option')) {
            update_option(self::OPTION_NAME, $this->settings, false);
        }

        RequestCache::rememberOption(self::class, self::OPTION_NAME, $this);
    }

    public function enabled(): bool
    {
        return !empty($this->settings['enabled']);
    }

    public function includeDatabase(): bool
    {
        return !empty($this->settings['include_database']);
    }

    public function maxFiles(): int
    {
        return (int) $this->settings['max_files'];
    }

    public function maxBytes(): int
    {
        return (int) $this->settings['max_bytes'];
    }

    public function retentionCount(): int
    {
        return (int) $this->settings['retention_count'];
    }

    public function allowFullSiteSnapshots(): bool
    {
        // This policy opt-in authorizes wp-config.php capture for ordinary
        // restore points. An explicit administrator-requested full backup
        // separately authorizes complete root capture.
        return !empty($this->settings['allow_full_site_snapshots']);
    }

    /**
     * @param array<int,string> $fallback
     * @return array<int,string>
     */
    public function defaultPaths(array $fallback): array
    {
        $paths = isset($this->settings['default_paths']) && is_array($this->settings['default_paths'])
            ? array_values(array_filter(array_map('strval', $this->settings['default_paths'])))
            : [];

        return empty($paths) ? $fallback : $paths;
    }

    /**
     * @param array<string,mixed> $settings
     * @return array<string,mixed>
     */
    public static function normalize(array $settings): array
    {
        $defaults = [
            'enabled' => true,
            'include_database' => true,
            'max_files' => 100000,
            'max_bytes' => 2147483648,
            'retention_count' => 10,
            'default_paths' => [],
            'allow_full_site_snapshots' => false,
        ];

        $settings = array_merge($defaults, $settings);

        $paths = [];
        if (isset($settings['default_paths']) && is_array($settings['default_paths'])) {
            foreach ($settings['default_paths'] as $path) {
                if (!is_scalar($path)) {
                    continue;
                }

                $path = trim(str_replace('\\', '/', (string) $path));
                if ($path === '' || strpos($path, "\0") !== false || strpos($path, '..') !== false) {
                    continue;
                }

                $paths[$path] = $path;
            }
        }

        return [
            'enabled' => !empty($settings['enabled']),
            'include_database' => !empty($settings['include_database']),
            'max_files' => max(1, min(100000, (int) $settings['max_files'])),
            'max_bytes' => max(1048576, min(2147483648, (int) $settings['max_bytes'])),
            'retention_count' => max(1, min(50, (int) $settings['retention_count'])),
            'default_paths' => array_values($paths),
            'allow_full_site_snapshots' => !empty($settings['allow_full_site_snapshots']),
        ];
    }
}
