<?php

namespace Tests\Feature\Imports;

use App\Jobs\SyncJobSource;
use App\Models\JobSource;
use App\Services\Settings\SettingsService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;

class SyncJobSourceTest extends TestCase
{
    use RefreshDatabase;

    public function test_json_sources_are_synced_and_marked_successful(): void
    {
        Http::fake([
            'https://feeds.example.test/jobs.json' => Http::response([
                'jobs' => [
                    [
                        'id' => 'sync-001',
                        'title' => 'Remote Sales Development Representative',
                        'company' => 'Pipeline Co',
                        'category' => 'sales',
                        'source_url' => 'https://feeds.example.test/jobs/sync-001',
                        'apply_url' => 'https://feeds.example.test/jobs/sync-001/apply',
                    ],
                ],
            ]),
        ]);

        $source = JobSource::query()->create([
            'name' => 'Sync JSON Feed',
            'slug' => 'sync-json-feed',
            'type' => 'json',
            'feed_url' => 'https://feeds.example.test/jobs.json',
            'is_active' => true,
            'sync_settings' => ['items_path' => 'jobs'],
        ]);

        app()->call([new SyncJobSource($source), 'handle']);

        $source->refresh();

        $this->assertNotNull($source->last_synced_at);
        $this->assertNull($source->last_failed_at);
        $this->assertDatabaseHas('imported_jobs', [
            'job_source_id' => $source->id,
            'external_id' => 'sync-001',
        ]);
    }

    public function test_api_sources_are_synced_with_configured_bearer_auth(): void
    {
        Http::fake([
            'https://api.example.test/jobs*' => Http::response([
                'data' => [
                    'jobs' => [
                        [
                            'id' => 'api-001',
                            'title' => 'Remote Finance Analyst',
                            'company' => 'Numbers Co',
                            'category' => 'finance',
                            'url' => 'https://api.example.test/jobs/api-001',
                            'apply_url' => 'https://api.example.test/jobs/api-001/apply',
                        ],
                    ],
                ],
            ]),
        ]);

        $source = JobSource::query()->create([
            'name' => 'API Feed',
            'slug' => 'api-feed',
            'type' => JobSource::TYPE_API,
            'feed_url' => 'https://api.example.test/jobs',
            'request_method' => 'get',
            'auth_type' => JobSource::AUTH_BEARER,
            'auth_secret' => 'api-secret-token',
            'request_headers' => ['User-Agent' => 'RemoteMatch Test'],
            'query_parameters' => ['remote' => 'true'],
            'is_active' => true,
            'sync_settings' => ['items_path' => 'data.jobs'],
        ]);

        app()->call([new SyncJobSource($source), 'handle']);

        Http::assertSent(fn ($request): bool => $request->hasHeader('Authorization', 'Bearer api-secret-token')
            && $request->hasHeader('User-Agent', 'RemoteMatch Test')
            && str_contains($request->url(), 'remote=true'));

        $source->refresh();

        $this->assertNotNull($source->last_synced_at);
        $this->assertDatabaseHas('imported_jobs', [
            'job_source_id' => $source->id,
            'external_id' => 'api-001',
            'title' => 'Remote Finance Analyst',
            'category' => 'finance',
        ]);
    }

    public function test_rss_sources_are_synced_from_xml_feed(): void
    {
        Http::fake([
            'https://feeds.example.test/jobs.xml' => Http::response(<<<'XML'
                <?xml version="1.0" encoding="UTF-8"?>
                <rss version="2.0">
                    <channel>
                        <title>Example Jobs</title>
                        <item>
                            <guid>rss-001</guid>
                            <title>Remote Customer Support Specialist</title>
                            <company>Care Co</company>
                            <category>support</category>
                            <link>https://feeds.example.test/jobs/rss-001</link>
                            <apply_url>https://feeds.example.test/jobs/rss-001/apply</apply_url>
                            <description>Help customers remotely.</description>
                            <pubDate>Wed, 17 Jun 2026 10:00:00 GMT</pubDate>
                        </item>
                    </channel>
                </rss>
            XML, 200, ['Content-Type' => 'application/rss+xml']),
        ]);

        $source = JobSource::query()->create([
            'name' => 'RSS Feed',
            'slug' => 'rss-feed',
            'type' => JobSource::TYPE_RSS,
            'feed_url' => 'https://feeds.example.test/jobs.xml',
            'is_active' => true,
            'sync_settings' => [
                'item_path' => 'channel.item',
                'title_path' => 'title',
                'company_path' => 'company',
                'source_url_path' => 'link',
                'apply_url_path' => 'apply_url',
                'external_id_path' => 'guid',
                'posted_at_path' => 'pubDate',
            ],
        ]);

        app()->call([new SyncJobSource($source), 'handle']);

        $source->refresh();

        $this->assertNotNull($source->last_synced_at);
        $this->assertDatabaseHas('imported_jobs', [
            'job_source_id' => $source->id,
            'external_id' => 'rss-001',
            'title' => 'Remote Customer Support Specialist',
            'company' => 'Care Co',
            'category' => 'support',
        ]);
    }

    public function test_we_work_remotely_style_rss_sources_are_synced_with_title_company_split_and_rss_fallback_path(): void
    {
        Http::fake([
            'https://weworkremotely.com/remote-jobs.rss' => Http::response(<<<'XML'
                <?xml version="1.0" encoding="UTF-8"?>
                <rss version="2.0">
                    <channel>
                        <title>We Work Remotely</title>
                        <item>
                            <guid>https://weworkremotely.com/remote-jobs/example-senior-web-developer</guid>
                            <title>Example Co: Senior Web Developer</title>
                            <region>Anywhere in the World</region>
                            <skills>Laravel, Tailwind CSS, Remote collaboration</skills>
                            <category>Back-End Programming</category>
                            <type>Full-Time</type>
                            <link>https://weworkremotely.com/remote-jobs/example-senior-web-developer</link>
                            <description>&lt;p&gt;Build production web products remotely. The annual base salary for this role is between $153,000 USD and $214,000 USD.&lt;/p&gt;</description>
                            <pubDate>Thu, 18 Jun 2026 02:19:12 +0000</pubDate>
                        </item>
                    </channel>
                </rss>
            XML, 200, ['Content-Type' => 'application/rss+xml']),
        ]);

        $source = JobSource::query()->updateOrCreate([
            'slug' => 'weworkremotely',
        ], [
            'name' => 'We Work Remotely RSS',
            'type' => JobSource::TYPE_RSS,
            'base_url' => 'https://weworkremotely.com/',
            'feed_url' => 'https://weworkremotely.com/remote-jobs.rss',
            'is_active' => true,
            'sync_settings' => [
                'item_path' => 'jobs.job',
                'title_path' => 'title',
                'company_path' => 'company',
                'source_url_path' => 'link',
                'apply_url_path' => 'apply_url',
                'external_id_path' => 'guid',
                'posted_at_path' => 'pubDate',
                'skills_path' => 'skills',
                'employment_type_path' => 'type',
                'location_text_path' => 'region',
            ],
        ]);

        app()->call([new SyncJobSource($source), 'handle']);

        $source->refresh();

        $this->assertNotNull($source->last_synced_at);
        $this->assertDatabaseHas('imported_jobs', [
            'job_source_id' => $source->id,
            'external_id' => 'https://weworkremotely.com/remote-jobs/example-senior-web-developer',
            'title' => 'Senior Web Developer',
            'company' => 'Example Co',
            'employment_type' => 'full_time',
            'salary_currency' => 'USD',
            'salary_min' => 153000,
            'salary_max' => 214000,
            'timezone' => 'Anywhere in the World',
            'status' => 'active',
        ]);

        $job = \App\Models\ImportedJob::query()->where('external_id', 'https://weworkremotely.com/remote-jobs/example-senior-web-developer')->firstOrFail();

        $this->assertStringNotContainsString('<p>', (string) $job->description);
        $this->assertStringContainsString('Build production web products remotely.', (string) $job->description);
    }

    public function test_sync_command_respects_global_job_source_enabled_setting(): void
    {
        Queue::fake();

        app(SettingsService::class)->set(
            group: 'job_sources',
            key: 'enabled',
            value: false,
            type: 'boolean',
        );

        JobSource::query()->create([
            'name' => 'Disabled Sync JSON Feed',
            'slug' => 'disabled-sync-json-feed',
            'type' => 'json',
            'feed_url' => 'https://feeds.example.test/jobs.json',
            'is_active' => true,
            'sync_settings' => ['items_path' => 'jobs'],
        ]);

        $this
            ->artisan('jobs:sync-sources')
            ->expectsOutput('Job source syncing is disabled in platform settings.')
            ->assertSuccessful();

        Queue::assertNothingPushed();
    }
}
