<?php

namespace PHPNative\Framework;

/**
 * Cross-platform settings manager
 * Stores application settings in JSON format in platform-appropriate directories
 */
class Settings
{
    private string $appName;
    private string $configPath;
    private array $data = [];
    private bool $loaded = false;

    public function __construct(string $appName)
    {
        $this->appName = $appName;
        $this->configPath = $this->getConfigPath();
        $this->ensureConfigDirectory();
    }

    /**
     * Get the platform-specific configuration directory
     */
    private function getConfigPath(): string
    {
        $os = PHP_OS_FAMILY;

        switch ($os) {
            case 'Windows':
                // Windows: %APPDATA%\AppName\config.json
                $appData = getenv('APPDATA') ?: (getenv('USERPROFILE') . '\\AppData\\Roaming');
                return $appData . DIRECTORY_SEPARATOR . $this->appName . DIRECTORY_SEPARATOR . 'config.json';

            case 'Darwin':
                // macOS: ~/Library/Application Support/AppName/config.json
                $home = getenv('HOME') ?: posix_getpwuid(posix_getuid())['dir'];
                return $home . '/Library/Application Support/' . $this->appName . '/config.json';

            case 'Linux':
            default:
                // Linux: ~/.config/AppName/config.json (XDG Base Directory)
                $xdgConfig = getenv('XDG_CONFIG_HOME');
                if (!$xdgConfig) {
                    $home = getenv('HOME') ?: posix_getpwuid(posix_getuid())['dir'];
                    $xdgConfig = $home . '/.config';
                }
                return $xdgConfig . DIRECTORY_SEPARATOR . $this->appName . DIRECTORY_SEPARATOR . 'config.json';
        }
    }

    /**
     * Ensure the configuration directory exists
     */
    private function ensureConfigDirectory(): void
    {
        $dir = dirname($this->configPath);
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
    }

    /**
     * Load settings from disk
     */
    private function load(): void
    {
        if ($this->loaded) {
            return;
        }

        if (file_exists($this->configPath)) {
            $contents = file_get_contents($this->configPath);
            $decoded = json_decode($contents, true);
            if (is_array($decoded)) {
                $this->data = $decoded;
            }
        }

        $this->loaded = true;
    }

    /**
     * Save settings to disk
     */
    public function save(): bool
    {
        $this->ensureConfigDirectory();

        $json = json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        if ($json === false) {
            return false;
        }

        return file_put_contents($this->configPath, $json, LOCK_EX) !== false;
    }

    /**
     * Get a setting value
     */
    public function get(string $key, mixed $default = null): mixed
    {
        $this->load();

        // Support dot notation for nested keys (e.g., "api.key")
        $keys = explode('.', $key);
        $value = $this->data;

        foreach ($keys as $k) {
            if (!is_array($value) || !array_key_exists($k, $value)) {
                return $default;
            }
            $value = $value[$k];
        }

        return $value;
    }

    /**
     * Set a setting value
     */
    public function set(string $key, mixed $value): void
    {
        $this->load();

        // Support dot notation for nested keys
        $keys = explode('.', $key);
        $current = &$this->data;

        foreach ($keys as $i => $k) {
            if ($i === count($keys) - 1) {
                // Last key - set the value
                $current[$k] = $value;
            } else {
                // Create nested array if it doesn't exist
                if (!isset($current[$k]) || !is_array($current[$k])) {
                    $current[$k] = [];
                }
                $current = &$current[$k];
            }
        }
    }

    /**
     * Check if a setting exists
     */
    public function has(string $key): bool
    {
        $this->load();

        $keys = explode('.', $key);
        $value = $this->data;

        foreach ($keys as $k) {
            if (!is_array($value) || !array_key_exists($k, $value)) {
                return false;
            }
            $value = $value[$k];
        }

        return true;
    }

    /**
     * Remove a setting
     */
    public function remove(string $key): void
    {
        $this->load();

        $keys = explode('.', $key);
        $current = &$this->data;

        foreach ($keys as $i => $k) {
            if ($i === count($keys) - 1) {
                // Last key - remove it
                unset($current[$k]);
            } else {
                if (!isset($current[$k]) || !is_array($current[$k])) {
                    return;
                }
                $current = &$current[$k];
            }
        }
    }

    /**
     * Get all settings as an array
     */
    public function all(): array
    {
        $this->load();
        return $this->data;
    }

    /**
     * Clear all settings
     */
    public function clear(): void
    {
        $this->data = [];
        $this->loaded = true;
    }

    /**
     * Get the path to the config file
     */
    public function getPath(): string
    {
        return $this->configPath;
    }
}
