<?php

namespace Tests\Feature\Settings;

use App\Filament\Pages\ManageSettings;
use App\Models\PlatformSetting;
use App\Models\SettingAuditLog;
use App\Models\User;
use App\Services\Settings\SettingsService;
use Database\Seeders\PlatformSettingSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Cache;
use Tests\TestCase;

class SettingsServiceTest extends TestCase
{
    use RefreshDatabase;

    public function test_database_settings_override_config_fallbacks(): void
    {
        config(['app.name' => 'Config RemoteMatch']);

        $settings = app(SettingsService::class);

        $this->assertSame('Config RemoteMatch', $settings->get('general.application_name'));

        $settings->set(
            group: 'general',
            key: 'application_name',
            value: 'Database RemoteMatch',
            type: 'string',
            encrypted: false,
            public: true,
        );

        $this->assertSame('Database RemoteMatch', $settings->get('general.application_name'));

        $record = PlatformSetting::query()
            ->where('group', 'general')
            ->where('key', 'application_name')
            ->firstOrFail();

        $this->assertTrue($record->is_public);
        $this->assertFalse($record->is_encrypted);
    }

    public function test_sensitive_settings_are_encrypted_and_audited_without_plain_values(): void
    {
        $settings = app(SettingsService::class);

        $settings->set(
            group: 'openai',
            key: 'api_key',
            value: 'sk-test-secret-value-123456',
            type: 'password',
            encrypted: true,
            public: false,
        );

        $record = PlatformSetting::query()
            ->where('group', 'openai')
            ->where('key', 'api_key')
            ->firstOrFail();

        $this->assertTrue($record->is_encrypted);
        $this->assertNotSame('sk-test-secret-value-123456', $record->value);
        $this->assertSame('sk-test-secret-value-123456', $settings->get('openai.api_key'));

        $auditLog = SettingAuditLog::query()->latest('id')->firstOrFail();

        $this->assertTrue($auditLog->is_secret);
        $this->assertSame('secret updated', $auditLog->new_value);
        $this->assertStringNotContainsString('sk-test-secret-value-123456', json_encode($auditLog->toArray()));
    }

    public function test_public_settings_only_return_public_non_secret_values(): void
    {
        $settings = app(SettingsService::class);

        $settings->set('branding', 'primary_color', '#0F766E', 'color', false, true);
        $settings->set('openai', 'api_key', 'sk-hidden-value', 'password', true, false);
        $settings->set('payment', 'razorpay_key_secret', 'rzp-hidden-value', 'password', true, false);

        $publicSettings = $settings->publicSettings();

        $this->assertSame('#0F766E', $publicSettings['branding.primary_color']);
        $this->assertArrayNotHasKey('openai.api_key', $publicSettings);
        $this->assertArrayNotHasKey('payment.razorpay_key_secret', $publicSettings);
    }

    public function test_it_recovers_from_an_invalid_cached_settings_payload(): void
    {
        $this->app->detectEnvironment(fn (): string => 'local');

        PlatformSetting::query()->create([
            'group' => 'general',
            'key' => 'application_name',
            'value' => 'Recovered RemoteMatch',
            'type' => 'string',
            'is_encrypted' => false,
            'is_public' => true,
        ]);

        Cache::forever(config('settings.cache_key'), new \stdClass);

        $this->assertSame(
            'Recovered RemoteMatch',
            app(SettingsService::class)->get('general.application_name')
        );
    }

    public function test_required_admin_setting_defaults_are_configured(): void
    {
        $paymentSettings = config('settings.groups.payment.settings');

        $this->assertStringEndsWith('/resume', $paymentSettings['payment_success_redirect_url']['default']);
        $this->assertStringEndsWith('/checkout', $paymentSettings['payment_failed_redirect_url']['default']);
        $this->assertStringEndsWith('/refund-policy', $paymentSettings['refund_policy_url']['default']);

        $googleSettings = config('settings.groups.google.settings');

        $this->assertSame('tags', $googleSettings['allowed_user_email_domains']['type']);
        $this->assertSame('ALLOWED_USER_EMAIL_DOMAINS', $googleSettings['allowed_user_email_domains']['env']);
        $this->assertSame('tags', $googleSettings['allowed_admin_email_domains']['type']);
        $this->assertSame('ALLOWED_ADMIN_EMAIL_DOMAINS', $googleSettings['allowed_admin_email_domains']['env']);
    }

    public function test_openai_model_settings_are_select_dropdowns(): void
    {
        $openAiSettings = config('settings.groups.openai.settings');
        $modelKeys = [
            'default_model',
            'resume_analysis_model',
            'questionnaire_generation_model',
            'job_matching_model',
            'cover_letter_model',
        ];

        foreach ($modelKeys as $modelKey) {
            $this->assertSame('select', $openAiSettings[$modelKey]['type']);
            $this->assertArrayHasKey('gpt-5.5', $openAiSettings[$modelKey]['options']);
            $this->assertArrayHasKey('gpt-5.4', $openAiSettings[$modelKey]['options']);
            $this->assertArrayHasKey('gpt-5.4-mini', $openAiSettings[$modelKey]['options']);
            $this->assertArrayHasKey('gpt-4.1-mini', $openAiSettings[$modelKey]['options']);
        }
    }

    public function test_platform_setting_seeder_backfills_blank_defaults_without_overwriting_admin_values(): void
    {
        $setting = PlatformSetting::query()->create([
            'group' => 'payment',
            'key' => 'payment_success_redirect_url',
            'value' => null,
            'type' => 'url',
            'is_encrypted' => false,
            'is_public' => false,
        ]);

        $this->seed(PlatformSettingSeeder::class);

        $this->assertStringEndsWith('/resume', $setting->refresh()->value);

        $setting->update(['value' => 'https://example.com/custom-success']);

        $this->seed(PlatformSettingSeeder::class);

        $this->assertSame('https://example.com/custom-success', $setting->refresh()->value);
    }

    public function test_admin_can_open_the_manage_settings_page(): void
    {
        $admin = User::factory()->create([
            'role' => 'admin',
        ]);

        $this
            ->actingAs($admin, 'admin')
            ->get(ManageSettings::getUrl(panel: 'admin'))
            ->assertOk()
            ->assertSee('Application name');
    }
}
