<?php

namespace Tests\Unit\Catalog;

use App\Domains\Cart\Services\ExpireCartReservationsService;
use App\Domains\Catalog\Services\ExpireStockReservationsService;
use App\Domains\Purchase\Services\CheckoutService;
use Illuminate\Support\Facades\Log;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Tests\TestCase;

class ExpireStockReservationsServiceTest extends TestCase
{
    public function test_it_expires_purchases_before_abandoned_cart_items(): void
    {
        $checkout = \Mockery::mock(CheckoutService::class);
        $checkout->shouldReceive('expireOverduePurchases')
            ->once()
            ->ordered()
            ->andReturn(2);

        $carts = \Mockery::mock(ExpireCartReservationsService::class);
        $carts->shouldReceive('expireOverdue')
            ->once()
            ->ordered()
            ->andReturn(3);

        $logger = \Mockery::mock(LoggerInterface::class);
        Log::shouldReceive('channel')
            ->once()
            ->with('commands')
            ->andReturn($logger);
        $logger->shouldReceive('info')
            ->once()
            ->with('Stock reservation cleanup completed.', [
                'command' => 'reservations:expire',
                'expired_purchases' => 2,
                'expired_cart_items' => 3,
                'total_expired' => 5,
            ]);

        $result = (new ExpireStockReservationsService($checkout, $carts))->expireOverdue();

        $this->assertSame([
            'purchases' => 2,
            'cart_items' => 3,
        ], $result);
    }

    public function test_it_logs_failed_cleanup_attempts_and_rethrows_the_error(): void
    {
        $exception = new RuntimeException('Unable to clean carts.');
        $checkout = \Mockery::mock(CheckoutService::class);
        $checkout->shouldReceive('expireOverduePurchases')->once()->andReturn(2);

        $carts = \Mockery::mock(ExpireCartReservationsService::class);
        $carts->shouldReceive('expireOverdue')->once()->andThrow($exception);

        $logger = \Mockery::mock(LoggerInterface::class);
        Log::shouldReceive('channel')
            ->once()
            ->with('commands')
            ->andReturn($logger);
        $logger->shouldReceive('error')
            ->once()
            ->with('Stock reservation cleanup failed.', [
                'command' => 'reservations:expire',
                'expired_purchases' => 2,
                'expired_cart_items' => null,
                'exception' => $exception,
            ]);

        $this->expectExceptionObject($exception);

        (new ExpireStockReservationsService($checkout, $carts))->expireOverdue();
    }
}
