<?php

namespace MintyPHP\Service\Settings;

class SettingCacheService
{
    private ?array $settings = null;
    private ?string $cacheFilePath;

    public function __construct(?string $cacheFilePath = null)
    {
        $this->cacheFilePath = $cacheFilePath;
    }

    public function get(string $key): ?string
    {
        $settings = $this->all();
        $value = $settings[$key] ?? null;
        if ($value === null) {
            return null;
        }
        $value = trim((string) $value);
        return $value !== '' ? $value : null;
    }

    public function all(): array
    {
        if ($this->settings !== null) {
            return $this->settings;
        }

        $file = $this->filePath();
        if (!is_file($file)) {
            $this->settings = [];
            return $this->settings;
        }

        $loaded = include $file;
        $this->settings = is_array($loaded) ? $loaded : [];
        return $this->settings;
    }

    public function update(array $values): bool
    {
        $current = $this->all();
        foreach ($values as $key => $value) {
            $settingKey = trim((string) $key);
            if ($settingKey === '') {
                continue;
            }
            $current[$settingKey] = $value === null ? null : (string) $value;
        }
        return $this->write($current);
    }

    public function write(array $settings): bool
    {
        $file = $this->filePath();
        $dir = dirname($file);
        if (!is_dir($dir) && !@mkdir($dir, 0775, true) && !is_dir($dir)) {
            return false;
        }

        // Write to a temp file first, then rename — rename is atomic on most filesystems,
        // so readers never see a half-written file. LOCK_EX prevents concurrent write corruption.
        $tmp = tempnam($dir, 'settings_');
        if ($tmp === false) {
            return false;
        }

        // PHP include returns an array — loaded by OPcache on subsequent requests, much faster than DB.
        $payload = "<?php\n\nreturn " . $this->exportValue($settings) . ";\n";
        $written = @file_put_contents($tmp, $payload, LOCK_EX);
        if ($written === false) {
            @unlink($tmp);
            return false;
        }

        if (!@rename($tmp, $file)) {
            @unlink($tmp);
            return false;
        }

        $this->settings = $settings;
        return true;
    }

    public function filePath(): string
    {
        if (is_string($this->cacheFilePath) && $this->cacheFilePath !== '') {
            return $this->cacheFilePath;
        }
        return dirname(__DIR__, 3) . '/config/settings.php';
    }

    private function exportValue(mixed $value, int $depth = 0): string
    {
        if (!is_array($value)) {
            return var_export($value, true);
        }

        if ($value === []) {
            return '[]';
        }

        $indent = str_repeat('    ', $depth);
        $childIndent = str_repeat('    ', $depth + 1);
        $lines = [];

        foreach ($value as $key => $item) {
            $lines[] = $childIndent
                . var_export($key, true)
                . ' => '
                . $this->exportValue($item, $depth + 1)
                . ',';
        }

        return "[\n" . implode("\n", $lines) . "\n" . $indent . ']';
    }
}
