<?php

namespace App\Services;

use App\Models\MexcoPlatformSetting;
use Illuminate\Support\Facades\Cache;

class SettingsService
{
    protected const CACHE_KEY = 'mexco.platform.settings';

    public function get(string $group, string $key, mixed $default = null): mixed
    {
        $all = $this->all();
        $compound = "{$group}.{$key}";

        if (array_key_exists($compound, $all)) {
            return $all[$compound];
        }

        return $default;
    }

    public function set(string $group, string $key, mixed $value, string $type = 'string'): MexcoPlatformSetting
    {
        $stored = match ($type) {
            'json' => json_encode($value),
            'boolean' => $value ? '1' : '0',
            default => (string) $value,
        };

        $setting = MexcoPlatformSetting::query()->updateOrCreate(
            ['group' => $group, 'key' => $key],
            ['value' => $stored, 'type' => $type]
        );

        Cache::forget(self::CACHE_KEY);

        return $setting;
    }

    public function grouped(): array
    {
        $rows = MexcoPlatformSetting::query()->orderBy('group')->orderBy('key')->get();
        $grouped = [];

        foreach ($rows as $row) {
            $grouped[$row->group][] = $row;
        }

        return $grouped;
    }

    public function definitions(): array
    {
        return [
            'general' => [
                'platform_name' => ['label' => 'Platform name', 'type' => 'string', 'default' => config('mexco.platform')],
                'support_email' => ['label' => 'Support email', 'type' => 'string', 'default' => 'support@mexco.local'],
            ],
            'business' => [
                'default_currency' => ['label' => 'Default currency', 'type' => 'string', 'default' => 'MYR'],
                'tax_rate_percent' => ['label' => 'Tax rate (%)', 'type' => 'integer', 'default' => config('mexco.billing.tax_rate_percent', 0)],
                'invoice_due_days' => ['label' => 'Invoice due days', 'type' => 'integer', 'default' => config('mexco.billing.default_due_days', 14)],
            ],
            'campus' => [
                'retention_days' => ['label' => 'Retention days', 'type' => 'integer', 'default' => config('mexco.campus.default_retention_days', 30)],
                'sponsorship_value_cents' => ['label' => 'Default sponsorship (sen)', 'type' => 'integer', 'default' => config('mexco.campus.default_sponsorship_value_cents', 99900)],
            ],
            'email' => [
                'from_name' => ['label' => 'From name', 'type' => 'string', 'default' => config('mexco.platform')],
                'from_address' => ['label' => 'From address', 'type' => 'string', 'default' => 'noreply@mexco.local'],
            ],
            'security' => [
                'require_strong_passwords' => ['label' => 'Require strong admin passwords', 'type' => 'boolean', 'default' => false],
            ],
            'trial' => [
                'enabled' => ['label' => 'Enable free demo', 'type' => 'boolean', 'default' => true],
                'duration_days' => ['label' => 'Demo duration (days)', 'type' => 'integer', 'default' => 10],
                'plan_code' => ['label' => 'Demo plan code', 'type' => 'string', 'default' => 'demo'],
                'one_per_organisation' => ['label' => 'One demo per organisation', 'type' => 'boolean', 'default' => true],
            ],
        ];
    }

    public function seedDefaults(): void
    {
        foreach ($this->definitions() as $group => $keys) {
            foreach ($keys as $key => $meta) {
                MexcoPlatformSetting::query()->firstOrCreate(
                    ['group' => $group, 'key' => $key],
                    ['value' => (string) $meta['default'], 'type' => $meta['type']]
                );
            }
        }

        Cache::forget(self::CACHE_KEY);
    }

    public function updateGroup(string $group, array $values): void
    {
        $definitions = $this->definitions()[$group] ?? [];

        foreach ($definitions as $key => $meta) {
            if (! array_key_exists($key, $values)) {
                if ($meta['type'] === 'boolean') {
                    $this->set($group, $key, false, 'boolean');
                }

                continue;
            }

            $value = $values[$key];
            if ($meta['type'] === 'boolean') {
                $value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
            }

            $this->set($group, $key, $value, $meta['type']);
        }
    }

    protected function all(): array
    {
        return Cache::remember(self::CACHE_KEY, 300, function () {
            $out = [];

            foreach (MexcoPlatformSetting::query()->get() as $row) {
                $out["{$row->group}.{$row->key}"] = $row->castValue();
            }

            return $out;
        });
    }
}
