<?php

namespace Daniv04\HaciendaPackage\Tests\Feature;

use Illuminate\Support\Facades\Mail;
use Daniv04\HaciendaPackage\Jobs\SendInvoiceEmailJob;
use Daniv04\HaciendaPackage\Mail\InvoiceAcceptedMail;
use Daniv04\HaciendaPackage\Services\Pdf\PdfGeneratorService;
use Daniv04\HaciendaPackage\Tests\TestCase;

class SendInvoiceEmailJobTest extends TestCase
{
    // -------------------------------------------------------------------------
    // Successful dispatch
    // -------------------------------------------------------------------------

    public function test_job_sends_email_to_recipient(): void
    {
        Mail::fake();

        $receipt = $this->makeReceipt();
        $this->makePayload($receipt->id);

        $this->mock(PdfGeneratorService::class)
             ->shouldReceive('generate')
             ->once()
             ->andReturn('%PDF-fake-content');

        (new SendInvoiceEmailJob($receipt, 'cliente@test.com'))->handle(
            app(PdfGeneratorService::class)
        );

        Mail::assertSent(InvoiceAcceptedMail::class, fn ($mail) => $mail->hasTo('cliente@test.com'));
    }

    public function test_job_sends_mail_with_correct_receipt(): void
    {
        Mail::fake();

        $receipt = $this->makeReceipt(['ui_key' => 'CLAVE-JOB-001']);
        $this->makePayload($receipt->id);

        $this->mock(PdfGeneratorService::class)
             ->shouldReceive('generate')
             ->andReturn('%PDF-fake-content');

        (new SendInvoiceEmailJob($receipt, 'receptor@test.com'))->handle(
            app(PdfGeneratorService::class)
        );

        Mail::assertSent(InvoiceAcceptedMail::class, function (InvoiceAcceptedMail $mail) use ($receipt) {
            return $mail->receipt->id === $receipt->id
                && $mail->hasTo('receptor@test.com');
        });
    }

    public function test_job_sends_exactly_one_email(): void
    {
        Mail::fake();

        $receipt = $this->makeReceipt();
        $this->makePayload($receipt->id);

        $this->mock(PdfGeneratorService::class)
             ->shouldReceive('generate')
             ->andReturn('%PDF-fake-content');

        (new SendInvoiceEmailJob($receipt, 'cliente@test.com'))->handle(
            app(PdfGeneratorService::class)
        );

        Mail::assertSentCount(1);
    }

    // -------------------------------------------------------------------------
    // PDF bytes passed to mailable
    // -------------------------------------------------------------------------

    public function test_pdf_bytes_from_service_are_passed_to_mailable(): void
    {
        Mail::fake();

        $receipt  = $this->makeReceipt(['ui_key' => 'CLAVE-PDF-001']);
        $this->makePayload($receipt->id);
        $fakePdf  = '%PDF-generated-content';

        $this->mock(PdfGeneratorService::class)
             ->shouldReceive('generate')
             ->andReturn($fakePdf);

        (new SendInvoiceEmailJob($receipt, 'test@example.com'))->handle(
            app(PdfGeneratorService::class)
        );

        Mail::assertSent(InvoiceAcceptedMail::class, fn ($mail) => $mail->pdfBytes === $fakePdf);
    }

    // -------------------------------------------------------------------------
    // Error handling
    // -------------------------------------------------------------------------

    public function test_job_rethrows_exception_so_queue_can_retry(): void
    {
        Mail::fake();

        $receipt = $this->makeReceipt();
        $this->makePayload($receipt->id);

        $this->mock(PdfGeneratorService::class)
             ->shouldReceive('generate')
             ->andThrow(new \RuntimeException('PDF generation failed'));

        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage('PDF generation failed');

        (new SendInvoiceEmailJob($receipt, 'cliente@test.com'))->handle(
            app(PdfGeneratorService::class)
        );
    }

    // -------------------------------------------------------------------------
    // failed() must NOT alter receipt_status
    // -------------------------------------------------------------------------

    public function test_failed_does_not_change_receipt_status(): void
    {
        $receipt = $this->makeReceipt(['receipt_status' => 'accepted']);

        $job = new SendInvoiceEmailJob($receipt, 'cliente@test.com');
        $job->failed(new \RuntimeException('Max retries exceeded'));

        $receipt->refresh();

        $this->assertSame('accepted', $receipt->receipt_status);
    }

    public function test_failed_does_not_change_hacienda_status(): void
    {
        $receipt = $this->makeReceipt(['hacienda_status' => 'accepted']);

        $job = new SendInvoiceEmailJob($receipt, 'cliente@test.com');
        $job->failed(new \RuntimeException('Max retries exceeded'));

        $receipt->refresh();

        $this->assertSame('accepted', $receipt->hacienda_status);
    }
}
