<?php

declare(strict_types=1);

namespace App\Services;

use App\Contracts\Services\SettingsServiceInterface;
use App\Models\Setting;
use Illuminate\Support\Facades\Cache;

final class SettingsService implements SettingsServiceInterface
{
    private const CACHE_KEY = 'app_settings';

    private const CACHE_TTL = 3600; // 1 hour

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

        return $settings[$key] ?? $default;
    }

    /**
     * Set a setting value
     */
    public function set(string $key, mixed $value, string $type = 'string', string $group = 'general'): void
    {
        // Convert value to string for storage
        $storedValue = match ($type) {
            'boolean' => $value ? '1' : '0',
            'json' => json_encode($value),
            'integer' => (string) $value,
            default => (string) $value,
        };

        Setting::updateOrCreate(
            ['key' => $key],
            [
                'value' => $storedValue,
                'type' => $type,
                'group' => $group,
            ]
        );

        $this->refresh();
    }

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

        return isset($settings[$key]);
    }

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

    /**
     * Get settings by group
     *
     * @return array<string, mixed>
     */
    public function getByGroup(string $group): array
    {
        $allSettings = Setting::where('group', $group)->get();

        $settings = [];
        foreach ($allSettings as $setting) {
            $settings[$setting->key] = $setting->getCastedValue();
        }

        return $settings;
    }

    /**
     * Delete a setting
     */
    public function delete(string $key): bool
    {
        $deleted = Setting::where('key', $key)->delete() > 0;

        if ($deleted) {
            $this->refresh();
        }

        return $deleted;
    }

    /**
     * Refresh settings cache
     */
    public function refresh(): void
    {
        Cache::forget(self::CACHE_KEY);
        $this->getCachedSettings();
    }

    /**
     * Get cached settings
     *
     * @return array<string, mixed>
     */
    private function getCachedSettings(): array
    {
        return Cache::remember(self::CACHE_KEY, self::CACHE_TTL, function () {
            $settings = [];

            foreach (Setting::all() as $setting) {
                $settings[$setting->key] = $setting->getCastedValue();
            }

            return $settings;
        });
    }
}
