<?php

namespace Tests\Feature\Resume;

use App\Jobs\AnalyzeResume;
use App\Models\ResumeReport;
use App\Models\User;
use App\Services\Settings\SettingsService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;

class ResumeUploadValidationTest extends TestCase
{
    use RefreshDatabase;

    public function test_unpaid_users_are_redirected_before_uploading_resume(): void
    {
        Storage::fake('local');
        Queue::fake();

        $user = User::factory()->create([
            'questionnaire_completed_at' => now(),
            'access_unlocked_at' => null,
        ]);

        $response = $this
            ->actingAs($user)
            ->post(route('resume.store'), [
                'resume' => UploadedFile::fake()->create('resume.txt', 4, 'text/plain'),
            ]);

        $response->assertRedirect(route('payment.checkout'));
        Queue::assertNothingPushed();
        $this->assertDatabaseCount('resume_reports', 0);
    }

    public function test_invalid_resume_file_type_is_rejected(): void
    {
        Storage::fake('local');
        Queue::fake();

        $user = User::factory()->create([
            'questionnaire_completed_at' => now(),
            'access_unlocked_at' => now(),
        ]);

        $response = $this
            ->actingAs($user)
            ->from(route('resume.show'))
            ->post(route('resume.store'), [
                'resume' => UploadedFile::fake()->create('resume.exe', 4, 'application/octet-stream'),
            ]);

        $response
            ->assertRedirect(route('resume.show'))
            ->assertSessionHasErrors('resume');

        Queue::assertNothingPushed();
        $this->assertDatabaseCount('resume_reports', 0);
    }

    public function test_valid_resume_upload_creates_pending_report_and_dispatches_analysis(): void
    {
        Storage::fake('local');
        Queue::fake();

        $user = User::factory()->create([
            'questionnaire_completed_at' => now(),
            'access_unlocked_at' => now(),
            'resume_uploaded_at' => null,
            'resume_analyzed_at' => now(),
        ]);

        $response = $this
            ->actingAs($user)
            ->post(route('resume.store'), [
                'resume' => UploadedFile::fake()->createWithContent(
                    'resume.pdf',
                    str_repeat('Remote operations and customer support experience. ', 6),
                ),
            ]);

        $response
            ->assertRedirect(route('resume.show'))
            ->assertSessionHas('status', 'Resume uploaded. Analysis has started.');

        $resumeReport = ResumeReport::query()->firstOrFail();

        $this->assertSame($user->id, $resumeReport->user_id);
        $this->assertSame('resume.pdf', $resumeReport->original_filename);
        $this->assertSame('local', $resumeReport->disk);
        $this->assertSame(ResumeReport::STATUS_PENDING, $resumeReport->status);
        $this->assertNull($resumeReport->analyzed_at);
        $this->assertNotNull($user->fresh()->resume_uploaded_at);
        $this->assertNull($user->fresh()->resume_analyzed_at);

        Storage::disk('local')->assertExists($resumeReport->path);
        Queue::assertPushed(AnalyzeResume::class);
    }

    public function test_resume_upload_can_return_json_for_live_analysis_ui(): void
    {
        Storage::fake('local');
        Queue::fake();

        $user = User::factory()->create([
            'questionnaire_completed_at' => now(),
            'access_unlocked_at' => now(),
            'resume_uploaded_at' => null,
            'resume_analyzed_at' => null,
        ]);

        $response = $this
            ->actingAs($user)
            ->postJson(route('resume.store'), [
                'resume' => UploadedFile::fake()->create('resume.pdf', 10, 'application/pdf'),
            ]);

        $response
            ->assertStatus(202)
            ->assertJsonPath('message', 'Resume uploaded. Analysis has started.')
            ->assertJsonPath('resume.status', ResumeReport::STATUS_PENDING)
            ->assertJsonPath('resume.filename', 'resume.pdf')
            ->assertJsonPath('resume.is_completed', false)
            ->assertJsonStructure([
                'status_url',
                'report_url',
                'resume' => [
                    'id',
                    'filename',
                    'status',
                    'status_label',
                    'extracted_skills',
                    'role_suggestions',
                    'missing_keywords',
                    'resume_improvements',
                    'profile_url',
                ],
            ]);

        Queue::assertPushed(AnalyzeResume::class);
    }

    public function test_resume_status_endpoint_returns_latest_report_payload(): void
    {
        $user = User::factory()->create([
            'questionnaire_completed_at' => now(),
            'access_unlocked_at' => now(),
        ]);

        $user->resumeReport()->create([
            'original_filename' => 'resume.pdf',
            'disk' => 'local',
            'path' => 'resumes/'.$user->id.'/resume.pdf',
            'mime_type' => 'application/pdf',
            'size_bytes' => 1024,
            'status' => ResumeReport::STATUS_COMPLETED,
            'ats_score' => 91,
            'remote_readiness_score' => 87,
            'extracted_skills' => ['Laravel', 'Support'],
            'role_suggestions' => ['Technical Support Specialist'],
            'missing_keywords' => ['SLA'],
            'resume_improvements' => ['Add remote collaboration examples.'],
            'analysis' => ['summary' => 'Strong technical support resume.'],
            'analyzed_at' => now(),
        ]);

        $response = $this
            ->actingAs($user)
            ->getJson(route('resume.status'));

        $response
            ->assertOk()
            ->assertJsonPath('resume.status', ResumeReport::STATUS_COMPLETED)
            ->assertJsonPath('resume.is_completed', true)
            ->assertJsonPath('resume.ats_score', 91)
            ->assertJsonPath('resume.extracted_skills.0', 'Laravel')
            ->assertJsonPath('resume.summary', 'Strong technical support resume.');
    }

    public function test_resume_upload_respects_admin_allowed_file_types_setting(): void
    {
        Storage::fake('local');
        Queue::fake();

        app(SettingsService::class)->set(
            group: 'resume',
            key: 'allowed_file_types',
            value: ['pdf', 'doc', 'docx', 'txt'],
            type: 'tags',
        );

        $user = User::factory()->create([
            'questionnaire_completed_at' => now(),
            'access_unlocked_at' => now(),
        ]);

        $response = $this
            ->actingAs($user)
            ->post(route('resume.store'), [
                'resume' => UploadedFile::fake()->createWithContent(
                    'resume.txt',
                    str_repeat('Remote operations and customer support experience. ', 6),
                ),
            ]);

        $response
            ->assertRedirect(route('resume.show'))
            ->assertSessionHas('status', 'Resume uploaded. Analysis has started.');

        $this->assertDatabaseHas('resume_reports', [
            'user_id' => $user->id,
            'original_filename' => 'resume.txt',
        ]);
    }

    public function test_resume_upload_respects_admin_maximum_file_size_setting(): void
    {
        Storage::fake('local');
        Queue::fake();

        app(SettingsService::class)->set(
            group: 'resume',
            key: 'maximum_file_size_mb',
            value: 1,
            type: 'integer',
        );

        $user = User::factory()->create([
            'questionnaire_completed_at' => now(),
            'access_unlocked_at' => now(),
        ]);

        $response = $this
            ->actingAs($user)
            ->from(route('resume.show'))
            ->post(route('resume.store'), [
                'resume' => UploadedFile::fake()->create('resume.pdf', 2048, 'application/pdf'),
            ]);

        $response
            ->assertRedirect(route('resume.show'))
            ->assertSessionHasErrors('resume');

        Queue::assertNothingPushed();
        $this->assertDatabaseCount('resume_reports', 0);
    }

    public function test_resume_reupload_can_be_disabled_from_admin_settings(): void
    {
        Storage::fake('local');
        Queue::fake();

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

        $user = User::factory()->create([
            'questionnaire_completed_at' => now(),
            'access_unlocked_at' => now(),
            'resume_uploaded_at' => now(),
        ]);

        $user->resumeReport()->create([
            'original_filename' => 'resume.pdf',
            'disk' => 'local',
            'path' => 'resumes/'.$user->id.'/resume.pdf',
            'mime_type' => 'application/pdf',
            'size_bytes' => 1024,
            'status' => ResumeReport::STATUS_COMPLETED,
        ]);

        $response = $this
            ->actingAs($user)
            ->post(route('resume.store'), [
                'resume' => UploadedFile::fake()->create('new-resume.pdf', 10, 'application/pdf'),
            ]);

        $response->assertForbidden();

        Queue::assertNothingPushed();
        $this->assertDatabaseCount('resume_reports', 1);
    }
}
