<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Mail;
use Mtc\Checkout\Contracts\InvoiceRepositoryContract;
use Mtc\Checkout\Events\PaidInvoice;
use Mtc\VehicleReservations\Jobs\NotifyTeamOfMoveRequestJob;
use Mtc\VehicleReservations\Listeners\ConfirmMoveRequestOnInvoicePayment;
use Mtc\VehicleReservations\Mail\VehicleMoveRequestedTeamMail;
use Mtc\VehicleReservations\MoveRequestRepository;
use Mtc\VehicleReservations\VehicleMoveRequest;
use Tests\TenantTestCase;

class MoveRequestPaymentConfirmationTest extends TenantTestCase
{
    private function listener(): ConfirmMoveRequestOnInvoicePayment
    {
        return new ConfirmMoveRequestOnInvoicePayment(new MoveRequestRepository());
    }

    private function paidInvoiceEvent($payable, string $reference, float $amount): PaidInvoice
    {
        $invoice = \Mockery::mock(InvoiceRepositoryContract::class);
        $invoice->shouldReceive('isPaid')->andReturnTrue();
        $invoice->shouldReceive('getPayable')->andReturn($payable);

        return new PaidInvoice($invoice, $reference, ['amount' => $amount]);
    }

    private function setRecipients(string $emails): void
    {
        Settings::make([
            'tab' => 'Automotive',
            'section' => 'Sales',
            'group' => 'Vehicle Moves',
            'name' => 'Move Request Recipient Email Address(es)',
            'config_key' => 'sales-vehicle-move-team-emails',
            'type' => 'string',
            'value' => $emails,
        ]);
    }

    public function testListenerMarksPaidAndDispatchesTheNotifyJob(): void
    {
        Bus::fake();
        $moveRequest = VehicleMoveRequest::factory()->create(['status' => 'pending']);

        $this->listener()->handle($this->paidInvoiceEvent($moveRequest, 'PAY-REF-1', 99.0));

        $moveRequest->refresh();
        $this->assertEquals('paid', $moveRequest->status);
        $this->assertEquals('PAY-REF-1', $moveRequest->payment_reference);
        $this->assertEquals(99.0, $moveRequest->amount);
        $this->assertNotNull($moveRequest->paid_at);

        Bus::assertDispatched(NotifyTeamOfMoveRequestJob::class);
    }

    public function testListenerIgnoresNonMovePayables(): void
    {
        Bus::fake();

        $this->listener()->handle($this->paidInvoiceEvent(new \stdClass(), 'PAY-REF-2', 99.0));

        Bus::assertNotDispatched(NotifyTeamOfMoveRequestJob::class);
    }

    public function testNotifyJobSendsMailAndStampsWhenRecipientsConfigured(): void
    {
        Mail::fake();
        $this->setRecipients('team@example.test');
        $moveRequest = VehicleMoveRequest::factory()->paid()->create(['team_notified_at' => null]);

        (new NotifyTeamOfMoveRequestJob($moveRequest))->handle(new MoveRequestRepository());

        Mail::assertSent(VehicleMoveRequestedTeamMail::class);
        $this->assertNotNull($moveRequest->fresh()->team_notified_at);
    }

    public function testNotifyJobSkipsWhenNoRecipientsConfigured(): void
    {
        Mail::fake();
        $moveRequest = VehicleMoveRequest::factory()->paid()->create(['team_notified_at' => null]);

        (new NotifyTeamOfMoveRequestJob($moveRequest))->handle(new MoveRequestRepository());

        Mail::assertNothingSent();
        $this->assertNull($moveRequest->fresh()->team_notified_at);
    }

    public function testNotifyJobIsIdempotentWhenAlreadyNotified(): void
    {
        Mail::fake();
        $this->setRecipients('team@example.test');
        $moveRequest = VehicleMoveRequest::factory()->paid()->create(['team_notified_at' => now()]);

        (new NotifyTeamOfMoveRequestJob($moveRequest))->handle(new MoveRequestRepository());

        Mail::assertNothingSent();
    }
}
