<?php

declare(strict_types=1);

class Setting
{
    private const MAX_CACHED_VALUE = 262144;

    private static array $cache = [];
    private static array $missing = [];
    private static bool $loaded = false;
    private static bool $complete = false;

    public static function loadAll(): void
    {
        if (self::$loaded) {
            return;
        }
        self::$loaded = true;
        $complete = true;
        $rows = Database::fetchAll('SELECT setting_key, setting_value FROM settings');
        foreach ($rows as $row) {
            if (strlen((string) $row['setting_value']) > self::MAX_CACHED_VALUE) {
                $complete = false;
                continue;
            }
            self::$cache[$row['setting_key']] = $row['setting_value'];
        }
        self::$complete = $complete;
    }

    public static function get(string $key, mixed $default = null): mixed
    {
        self::loadAll();

        if (array_key_exists($key, self::$cache)) {
            return self::$cache[$key];
        }

        if (self::$complete || isset(self::$missing[$key])) {
            return $default;
        }

        $row = Database::fetchOne('SELECT setting_value FROM settings WHERE setting_key = ?', [$key]);
        if ($row !== null) {
            self::$cache[$key] = $row['setting_value'];
            return $row['setting_value'];
        }

        self::$missing[$key] = true;
        return $default;
    }

    public static function set(string $key, mixed $value): void
    {
        Database::query(
            'INSERT INTO settings (setting_key, setting_value, autoload) VALUES (?, ?, 1)
             ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)',
            [$key, (string) $value]
        );
        self::$cache[$key] = (string) $value;
        unset(self::$missing[$key]);
    }

    public static function delete(string $key): void
    {
        Database::query('DELETE FROM settings WHERE setting_key = ?', [$key]);
        unset(self::$cache[$key]);
        self::$missing[$key] = true;
    }

    public static function deleteByPrefix(string $prefix): void
    {
        Database::query('DELETE FROM settings WHERE setting_key LIKE ?', [$prefix . '%']);
        foreach (array_keys(self::$cache) as $k) {
            if (str_starts_with($k, $prefix)) {
                unset(self::$cache[$k]);
            }
        }
    }

    public static function getMany(array $keys): array
    {
        $result = [];
        foreach ($keys as $key) {
            $result[$key] = self::get($key);
        }
        return $result;
    }

    public static function clearCache(): void
    {
        self::$cache = [];
        self::$missing = [];
        self::$loaded = false;
        self::$complete = false;
    }

    

    public static function getDirect(string $key, mixed $default = null): mixed
    {
        $row = Database::fetchOne('SELECT setting_value FROM settings WHERE setting_key = ?', [$key]);
        if ($row !== null) {
            return $row['setting_value'];
        }
        return $default;
    }

    public static function all(): array
    {
        return Database::fetchAll('SELECT setting_key, setting_value FROM settings');
    }
}
