<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use Database\Seeders\Tenant\SettingsDefinitionSeeder;
use Illuminate\Support\Facades\DB;
use Mtc\MercuryDataModels\Setting;
use Tests\TenantTestCase;

class SettingsDefinitionSeederTest extends TenantTestCase
{
    protected bool $needsMasterDatabase = true;
    protected bool $useTestSettingRepository = false;

    private function sampleSettings(): array
    {
        return [
            [
                'tab' => 'Site',
                'section' => 'General',
                'group' => 'Test',
                'name' => 'Test Setting',
                'config_key' => 'test-setting-one',
                'type' => 'string',
                'value' => 'default-value',
                'order' => 1,
                'description' => 'A test setting',
            ],
            [
                'tab' => 'Site',
                'section' => 'General',
                'group' => 'Test',
                'name' => 'Test Boolean',
                'config_key' => 'test-setting-two',
                'type' => 'boolean',
                'value' => true,
                'order' => 2,
            ],
        ];
    }

    public function testSettingsAreCreatedOnFirstRun(): void
    {
        $seeder = new SettingsDefinitionSeeder();
        $seeder->run($this->sampleSettings());

        $this->assertCount(2, Setting::all());
        $this->assertEquals('default-value', Setting::where('config_key', 'test-setting-one')->first()->value);
        $this->assertEquals(true, Setting::where('config_key', 'test-setting-two')->first()->value);
    }

    public function testUserValueIsPreservedOnReRun(): void
    {
        $seeder = new SettingsDefinitionSeeder();
        $seeder->run($this->sampleSettings());

        Settings::update('test-setting-one', 'user-changed-value');

        $this->assertEquals('user-changed-value', Setting::where('config_key', 'test-setting-one')->first()->value);

        $seeder->run($this->sampleSettings());

        $this->assertEquals(
            'user-changed-value',
            Setting::where('config_key', 'test-setting-one')->first()->value,
            'User-set value should not be overwritten by seeder re-run'
        );
    }

    public function testMetadataIsUpdatedOnReRun(): void
    {
        $seeder = new SettingsDefinitionSeeder();
        $seeder->run($this->sampleSettings());

        $this->assertEquals(1, Setting::where('config_key', 'test-setting-one')->first()->order);
        $this->assertEquals('A test setting', Setting::where('config_key', 'test-setting-one')->first()->description);
        $this->assertEquals('General', Setting::where('config_key', 'test-setting-one')->first()->section);

        $updatedSettings = $this->sampleSettings();
        $updatedSettings[0]['order'] = 50;
        $updatedSettings[0]['description'] = 'Updated description';
        $updatedSettings[0]['section'] = 'Advanced';

        $seeder->run($updatedSettings);

        $setting = Setting::where('config_key', 'test-setting-one')->first();
        $this->assertEquals(50, $setting->order);
        $this->assertEquals('Updated description', $setting->description);
        $this->assertEquals('Advanced', $setting->section);
    }

    public function testOrphanedSettingsAreDeleted(): void
    {
        Settings::make([
            'tab' => 'Site',
            'section' => 'General',
            'group' => 'Orphan',
            'name' => 'Orphan Setting',
            'config_key' => 'orphan-setting',
            'type' => 'string',
            'value' => 'will-be-deleted',
        ]);

        $this->assertNotNull(Setting::where('config_key', 'orphan-setting')->first());

        $seeder = new SettingsDefinitionSeeder();
        $seeder->run($this->sampleSettings());

        $this->assertNull(
            Setting::where('config_key', 'orphan-setting')->first(),
            'Setting not in definitions file should be deleted'
        );
        $this->assertCount(2, Setting::all());
    }

    public function testDataOnlySettingsAreNotDeleted(): void
    {
        DB::table('settings')->insert([
            'config_key' => 'internal-data-key',
            'tab' => '',
            'section' => '',
            'group' => '',
            'name' => '',
            'type' => 'string',
            'data' => json_encode(['some' => 'data']),
        ]);

        $seeder = new SettingsDefinitionSeeder();
        $seeder->run($this->sampleSettings());

        $this->assertNotNull(
            Setting::where('config_key', 'internal-data-key')->first(),
            'Data-only settings (empty tab) should not be deleted by orphan cleanup'
        );
        $this->assertCount(3, Setting::all());
    }

    public function testClosureValuesAreResolved(): void
    {
        $settings = [
            [
                'tab' => 'Site',
                'section' => 'General',
                'group' => 'Test',
                'name' => 'Dynamic Setting',
                'config_key' => 'test-dynamic',
                'type' => 'string',
                'value' => fn () => 'resolved-' . 'value',
                'description' => fn () => 'Dynamic ' . 'description',
            ],
        ];

        $seeder = new SettingsDefinitionSeeder();
        $seeder->run($settings);

        $setting = Setting::where('config_key', 'test-dynamic')->first();
        $this->assertEquals('resolved-value', $setting->value);
        $this->assertEquals('Dynamic description', $setting->description);
    }
}
