<?php

namespace Tests\Feature\Admin;

use App\Jobs\SyncJobSource;
use App\Models\Application;
use App\Models\EmailDeliveryLog;
use App\Models\ImportedJob;
use App\Models\JobSource;
use App\Models\Profile;
use App\Models\QuestionnaireResponse;
use App\Models\ResumeReport;
use App\Models\User;
use App\Services\Email\EmailResendService;
use App\Services\Jobs\JsonFeedJobImporter;
use App\Services\Jobs\XmlFeedJobImporter;
use App\Services\Settings\SettingsService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

class OperationsModulesTest extends TestCase
{
    use RefreshDatabase;

    public function test_job_alert_delivery_log_stores_brevo_message_id_and_webhook_updates_metrics(): void
    {
        Http::fake([
            'https://api.brevo.com/v3/smtp/email' => Http::response(['messageId' => 'brevo-alert-001'], 201),
        ]);

        $this->configureBrevo();
        $user = $this->unlockedUser();
        $this->remoteJob();

        $this
            ->artisan('jobs:send-daily-alerts', ['--user' => $user->email])
            ->assertSuccessful();

        $this->assertDatabaseHas('email_delivery_logs', [
            'user_id' => $user->id,
            'type' => EmailDeliveryLog::TYPE_JOB_ALERT,
            'status' => EmailDeliveryLog::STATUS_SENT,
            'brevo_message_id' => 'brevo-alert-001',
        ]);

        $this->assertDatabaseHas('job_alert_email_logs', [
            'user_id' => $user->id,
            'status' => 'sent',
            'brevo_message_id' => 'brevo-alert-001',
        ]);

        $this
            ->withHeader('X-Brevo-Webhook-Secret', 'webhook-secret')
            ->postJson(route('webhooks.brevo.email-events'), [
                'event' => 'opened',
                'messageId' => 'brevo-alert-001',
                'date' => now()->toIso8601String(),
            ])
            ->assertOk()
            ->assertJsonPath('processed', 1);

        $deliveryLog = EmailDeliveryLog::query()->where('brevo_message_id', 'brevo-alert-001')->firstOrFail();
        $this->assertSame(EmailDeliveryLog::STATUS_OPENED, $deliveryLog->status);
        $this->assertNotNull($deliveryLog->opened_at);
        $this->assertDatabaseHas('user_engagement_events', [
            'user_id' => $user->id,
            'event_type' => 'email_opened',
        ]);

        $this->assertNotNull($user->jobAlertEmailLogs()->firstOrFail()->opened_at);
    }

    public function test_failed_job_alert_email_can_be_manually_resent(): void
    {
        Http::fake([
            'https://api.brevo.com/v3/smtp/email' => Http::sequence()
                ->push(['message' => 'temporary failure'], 500)
                ->push(['messageId' => 'brevo-resent-001'], 201),
        ]);

        $this->configureBrevo();
        $user = $this->unlockedUser();
        $this->remoteJob();

        $this
            ->artisan('jobs:send-daily-alerts', ['--user' => $user->email])
            ->assertFailed();

        $failedLog = EmailDeliveryLog::query()
            ->where('type', EmailDeliveryLog::TYPE_JOB_ALERT)
            ->where('status', EmailDeliveryLog::STATUS_FAILED)
            ->firstOrFail();

        $resentLog = app(EmailResendService::class)->resend($failedLog);

        $this->assertSame(EmailDeliveryLog::STATUS_SENT, $resentLog->status);
        $this->assertSame('brevo-resent-001', $resentLog->brevo_message_id);
        $this->assertSame($failedLog->id, $resentLog->metadata['resent_from_email_delivery_log_id'] ?? null);
    }

    public function test_admin_can_export_applicants_and_applications_without_public_apply_urls(): void
    {
        $admin = User::factory()->create(['role' => 'admin']);
        $user = $this->unlockedUser();
        $job = $this->remoteJob(['apply_url' => 'https://apply.example/private-url']);

        Application::query()->create([
            'user_id' => $user->id,
            'imported_job_id' => $job->id,
            'job_source_id' => $job->job_source_id,
            'source_url' => $job->source_url,
            'apply_url' => $job->apply_url,
            'source_attribution' => $job->attribution(),
            'status' => Application::STATUS_APPLIED,
            'applied_at' => now(),
        ]);

        $applicantExport = $this
            ->actingAs($admin, 'admin')
            ->get(route('admin.exports.applicants'))
            ->assertOk();

        $applicantCsv = $applicantExport->streamedContent();
        $this->assertStringContainsString($user->email, $applicantCsv);
        $this->assertStringContainsString('resume.pdf', $applicantCsv);

        $applicationExport = $this
            ->actingAs($admin, 'admin')
            ->get(route('admin.exports.applications'))
            ->assertOk();

        $applicationCsv = $applicationExport->streamedContent();
        $this->assertStringContainsString($job->title, $applicationCsv);
        $this->assertStringContainsString($user->email, $applicationCsv);
        $this->assertStringNotContainsString('https://apply.example/private-url', $applicationCsv);
    }

    public function test_job_source_sync_logs_are_recorded_for_health_dashboard(): void
    {
        $source = JobSource::query()->create([
            'name' => 'Manual Health Source',
            'slug' => 'manual-health-source',
            'type' => JobSource::TYPE_MANUAL,
            'is_active' => true,
        ]);

        (new SyncJobSource($source))->handle(app(JsonFeedJobImporter::class), app(XmlFeedJobImporter::class));

        $this->assertDatabaseHas('job_source_sync_logs', [
            'job_source_id' => $source->id,
            'status' => 'success',
            'jobs_imported' => 0,
            'jobs_expired' => 0,
        ]);

        $this->assertNotNull($source->fresh()->last_synced_at);
    }

    public function test_user_engagement_timeline_records_job_save_action(): void
    {
        $user = $this->unlockedUser();
        $job = $this->remoteJob();

        $this
            ->actingAs($user)
            ->post(route('jobs.save', $job))
            ->assertRedirect();

        $this->assertDatabaseHas('user_engagement_events', [
            'user_id' => $user->id,
            'event_type' => 'job_saved',
        ]);
    }

    private function configureBrevo(): void
    {
        app(SettingsService::class)->set('email', 'brevo_enabled', true, 'boolean');
        app(SettingsService::class)->set('email', 'brevo_api_key', 'brevo-secret-key', 'password', encrypted: true);
        app(SettingsService::class)->set('email', 'brevo_webhook_secret', 'webhook-secret', 'password', encrypted: true);
        app(SettingsService::class)->set('notifications', 'new_matched_jobs_email_enabled', true, 'boolean');
    }

    private function unlockedUser(): User
    {
        $user = User::factory()->create([
            'email' => 'operations-user@example.com',
            'questionnaire_completed_at' => now(),
            'access_unlocked_at' => now(),
            'resume_uploaded_at' => now(),
            'resume_analyzed_at' => now(),
            'profile_completed_at' => now(),
        ]);

        QuestionnaireResponse::query()->create([
            'user_id' => $user->id,
            'answers' => [],
            'preferred_categories' => ['design'],
            'preferred_roles' => ['product designer'],
            'skills' => ['Figma', 'UI/UX'],
            'experience_level' => 'mid',
            'salary_currency' => 'USD',
            'salary_min' => 80000,
            'open_to_full_time' => true,
            'completed_at' => now(),
        ]);

        ResumeReport::query()->create([
            'user_id' => $user->id,
            'is_current' => true,
            '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' => 82,
            'remote_readiness_score' => 90,
            'extracted_skills' => ['Figma', 'UI/UX'],
            'role_suggestions' => ['product designer'],
            'missing_keywords' => [],
            'resume_improvements' => [],
            'analysis' => [],
            'analyzed_at' => now(),
        ]);

        Profile::query()->create([
            'user_id' => $user->id,
            'headline' => 'Remote product designer',
            'summary' => 'Designs SaaS product experiences.',
            'current_role' => 'Product Designer',
            'experience_level' => 'mid',
            'skills' => ['Figma', 'UI/UX'],
            'preferred_roles' => ['product designer'],
            'preferred_categories' => ['design'],
            'salary_currency' => 'USD',
            'salary_min' => 80000,
            'open_to_full_time' => true,
            'completed_at' => now(),
        ]);

        return $user;
    }

    /**
     * @param  array<string, mixed>  $overrides
     */
    private function remoteJob(array $overrides = []): ImportedJob
    {
        $source = JobSource::query()->firstOrCreate(
            ['slug' => 'operations-source'],
            [
                'name' => 'Operations Source',
                'type' => JobSource::TYPE_MANUAL,
                'base_url' => 'https://jobs.example',
                'attribution_text' => 'Source: Operations Source',
                'is_active' => true,
            ],
        );

        return ImportedJob::query()->create(array_replace([
            'job_source_id' => $source->id,
            'external_id' => 'operations-001',
            'title' => 'Senior Product Designer',
            'company' => 'Remote Design Co',
            'category' => 'design',
            'employment_type' => 'full_time',
            'experience_level' => 'mid',
            'location_type' => 'remote',
            'salary_currency' => 'USD',
            'salary_min' => 90000,
            'salary_max' => 120000,
            'summary' => 'Design remote SaaS workflows.',
            'description' => 'Lead UI/UX work for a distributed SaaS product team.',
            'skills' => ['Figma', 'UI/UX'],
            'tags' => ['remote', 'design'],
            'source_url' => 'https://jobs.example/roles/designer',
            'apply_url' => 'https://jobs.example/roles/designer/apply',
            'source_attribution' => 'Source: Operations Source',
            'status' => ImportedJob::STATUS_ACTIVE,
            'posted_at' => now(),
            'last_seen_at' => now(),
        ], $overrides));
    }
}
