<?php

use App\Notifications\QueueFailureNotification;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Notifications\AnonymousNotifiable;
use Illuminate\Queue\Events\JobFailed;
use Illuminate\Support\Facades\Notification;

beforeEach(function () {
    config([
        'libra.notifications.system_notifications_enabled' => true,
        'libra.notifications.admin_email' => 'admin@libra.ps',
        'libra.notifications.throttle_minutes' => 15,
    ]);
});

test('queue failure notification contains job information', function () {
    $job = Mockery::mock(Job::class);
    $job->shouldReceive('resolveName')->andReturn('App\\Jobs\\SendEmailJob');
    $job->shouldReceive('getQueue')->andReturn('default');
    $job->shouldReceive('attempts')->andReturn(3);

    $exception = new RuntimeException('Job processing failed');
    $event = new JobFailed('database', $job, $exception);

    $notification = new QueueFailureNotification($event);
    $mail = $notification->toMail(new AnonymousNotifiable);

    expect($mail->subject)->toContain('[URGENT]');
    expect($mail->subject)->toContain('Queue Job Failed');
    expect($mail->subject)->toContain('SendEmailJob');
    expect($mail->subject)->toContain('Libra Law Firm');
});

test('queue failure notification includes environment', function () {
    $job = Mockery::mock(Job::class);
    $job->shouldReceive('resolveName')->andReturn('TestJob');
    $job->shouldReceive('getQueue')->andReturn('default');
    $job->shouldReceive('attempts')->andReturn(1);

    $exception = new RuntimeException('Failed');
    $event = new JobFailed('database', $job, $exception);

    $notification = new QueueFailureNotification($event);
    $mail = $notification->toMail(new AnonymousNotifiable);

    expect($mail->subject)->toContain('['.app()->environment().']');
});

test('queue failure notification array contains required data', function () {
    $job = Mockery::mock(Job::class);
    $job->shouldReceive('resolveName')->andReturn('App\\Jobs\\TestJob');
    $job->shouldReceive('getQueue')->andReturn('emails');
    $job->shouldReceive('attempts')->andReturn(2);

    $exception = new RuntimeException('Test failure');
    $event = new JobFailed('database', $job, $exception);

    $notification = new QueueFailureNotification($event);
    $array = $notification->toArray(new AnonymousNotifiable);

    expect($array)->toHaveKey('type', 'queue_failure');
    expect($array)->toHaveKey('job', 'App\\Jobs\\TestJob');
    expect($array)->toHaveKey('queue', 'emails');
});

test('queue failure listener sends notification when enabled', function () {
    Notification::fake();

    $job = Mockery::mock(Job::class);
    $job->shouldReceive('resolveName')->andReturn('TestJob');
    $job->shouldReceive('getQueue')->andReturn('default');
    $job->shouldReceive('attempts')->andReturn(1);

    $exception = new RuntimeException('Failed');
    $event = new JobFailed('database', $job, $exception);

    event($event);

    Notification::assertSentOnDemand(
        QueueFailureNotification::class,
        function ($notification, $channels, $notifiable) {
            return $notifiable->routes['mail'] === config('libra.notifications.admin_email');
        }
    );
});

test('queue failure listener does not send notification when disabled', function () {
    Notification::fake();
    config(['libra.notifications.system_notifications_enabled' => false]);

    $job = Mockery::mock(Job::class);
    $job->shouldReceive('resolveName')->andReturn('TestJob');
    $job->shouldReceive('getQueue')->andReturn('default');
    $job->shouldReceive('attempts')->andReturn(1);

    $exception = new RuntimeException('Failed');
    $event = new JobFailed('database', $job, $exception);

    event($event);

    Notification::assertNothingSent();
});

test('queue failure listener does not send notification when admin email not configured', function () {
    Notification::fake();
    config(['libra.notifications.admin_email' => null]);

    $job = Mockery::mock(Job::class);
    $job->shouldReceive('resolveName')->andReturn('TestJob');
    $job->shouldReceive('getQueue')->andReturn('default');
    $job->shouldReceive('attempts')->andReturn(1);

    $exception = new RuntimeException('Failed');
    $event = new JobFailed('database', $job, $exception);

    event($event);

    Notification::assertNothingSent();
});
