<?php

namespace Tests\Feature\Jobs;

use App\Contracts\ResumeAnalyzer;
use App\Contracts\ResumeTextExtractor;
use App\Jobs\AnalyzeResume;
use App\Models\ResumeReport;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use RuntimeException;
use Tests\TestCase;

class AnalyzeResumeTest extends TestCase
{
    use RefreshDatabase;

    public function test_it_marks_resume_report_completed_after_successful_analysis(): void
    {
        $resumeReport = $this->resumeReport();

        (new AnalyzeResume($resumeReport))->handle(
            $this->extractor(str_repeat('Remote product marketer with SEO, analytics, lifecycle campaigns, and async collaboration. ', 3)),
            $this->analyzer([
                'ats_score' => 91,
                'remote_readiness_score' => 86,
                'extracted_skills' => ['SEO', 'Analytics'],
                'role_suggestions' => ['Growth Marketer'],
                'missing_keywords' => ['CRM'],
                'resume_improvements' => ['Add quantified campaign outcomes.'],
                'summary' => 'Strong remote marketing candidate.',
            ]),
        );

        $resumeReport->refresh();

        $this->assertSame(ResumeReport::STATUS_COMPLETED, $resumeReport->status);
        $this->assertSame(91, $resumeReport->ats_score);
        $this->assertSame(86, $resumeReport->remote_readiness_score);
        $this->assertSame(['SEO', 'Analytics'], $resumeReport->extracted_skills);
        $this->assertSame(['Growth Marketer'], $resumeReport->role_suggestions);
        $this->assertNotNull($resumeReport->analyzed_at);
        $this->assertNotNull($resumeReport->user->fresh()->resume_analyzed_at);
    }

    public function test_it_fails_when_extracted_resume_text_is_too_short(): void
    {
        $resumeReport = $this->resumeReport();

        (new AnalyzeResume($resumeReport))->handle(
            $this->extractor('Too short.'),
            $this->failingAnalyzer('Analyzer should not be called for short resume text.'),
        );

        $resumeReport->refresh();

        $this->assertSame(ResumeReport::STATUS_FAILED, $resumeReport->status);
        $this->assertSame('Resume text could not be extracted clearly enough for analysis.', $resumeReport->failure_reason);
        $this->assertNull($resumeReport->analyzed_at);
        $this->assertNull($resumeReport->user->fresh()->resume_analyzed_at);
    }

    public function test_it_fails_safely_when_analysis_throws(): void
    {
        $resumeReport = $this->resumeReport();

        (new AnalyzeResume($resumeReport))->handle(
            $this->extractor(str_repeat('Remote support specialist with CRM, customer success, documentation, and async handoffs. ', 3)),
            $this->failingAnalyzer('Provider failed.'),
        );

        $resumeReport->refresh();

        $this->assertSame(ResumeReport::STATUS_FAILED, $resumeReport->status);
        $this->assertSame('Resume analysis failed. Please try uploading again.', $resumeReport->failure_reason);
        $this->assertNull($resumeReport->analyzed_at);
    }

    private function resumeReport(): ResumeReport
    {
        return ResumeReport::query()->create([
            'user_id' => User::factory()->create()->id,
            'original_filename' => 'resume.txt',
            'disk' => 'local',
            'path' => 'resumes/1/resume.txt',
            'mime_type' => 'text/plain',
            'size_bytes' => 2048,
            'status' => ResumeReport::STATUS_PENDING,
        ]);
    }

    private function extractor(string $text): ResumeTextExtractor
    {
        return new class($text) implements ResumeTextExtractor
        {
            public function __construct(private readonly string $text) {}

            public function extract(ResumeReport $resumeReport): string
            {
                return $this->text;
            }
        };
    }

    /**
     * @param  array<string, mixed>  $analysis
     */
    private function analyzer(array $analysis): ResumeAnalyzer
    {
        return new class($analysis) implements ResumeAnalyzer
        {
            /**
             * @param  array<string, mixed>  $analysis
             */
            public function __construct(private readonly array $analysis) {}

            /**
             * @return array<string, mixed>
             */
            public function analyze(string $resumeText): array
            {
                return $this->analysis;
            }
        };
    }

    private function failingAnalyzer(string $message): ResumeAnalyzer
    {
        return new class($message) implements ResumeAnalyzer
        {
            public function __construct(private readonly string $message) {}

            public function analyze(string $resumeText): array
            {
                throw new RuntimeException($this->message);
            }
        };
    }
}
