<?php

declare(strict_types=1);

namespace Autogedal\AwbRetry\Test\Unit\Plugin;

use Autogedal\AwbRetry\Model\AwbErrorLogManager;
use Autogedal\AwbRetry\Model\Config;
use Autogedal\AwbRetry\Model\Queue\RetryRequestPublisher;
use Autogedal\AwbRetry\Model\TransientFailureClassifier;
use Autogedal\AwbRetry\Plugin\CourierGenerateAwbRetryPlugin;
use Eadesigndev\Awb\Model\AwbRepository;
use Magento\Framework\DataObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

class CourierGenerateAwbRetryPluginTest extends TestCase
{
    public function testLaterCourierSuccessSynchronizesExistingLog(): void
    {
        $manager = $this->createMock(AwbErrorLogManager::class);
        $manager->expects(self::once())->method('resolveForAwb')->with(125094, 5, '95316064')->willReturn(true);
        $manager->expects(self::never())->method('upsertFailure');
        $publisher = $this->createMock(RetryRequestPublisher::class);
        $publisher->expects(self::never())->method('queue');
        $plugin = $this->createPlugin($manager, $publisher, $this->createMock(LoggerInterface::class));

        self::assertSame('95316064', $plugin->aroundGenerateAwb(new \stdClass(), fn () => '95316064', 125094));
    }

    public function testSynchronizationFailureDoesNotRetrySuccessfulCourierCall(): void
    {
        $manager = $this->createMock(AwbErrorLogManager::class);
        $manager->method('resolveForAwb')->willThrowException(new \RuntimeException('Database write failed'));
        $manager->expects(self::never())->method('upsertFailure');
        $publisher = $this->createMock(RetryRequestPublisher::class);
        $publisher->expects(self::never())->method('queue');
        $logger = $this->createMock(LoggerInterface::class);
        $logger->expects(self::once())->method('error');
        $plugin = $this->createPlugin($manager, $publisher, $logger);
        $calls = 0;

        self::assertSame('95316064', $plugin->aroundGenerateAwb(new \stdClass(), function () use (&$calls) {
            ++$calls;
            return '95316064';
        }, 125094));
        self::assertSame(1, $calls);
    }

    public function testSuccessWithoutPriorFailureKeepsOriginalReturnValue(): void
    {
        $manager = $this->createMock(AwbErrorLogManager::class);
        $manager->method('resolveForAwb')->willReturn(false);
        $manager->expects(self::never())->method('upsertFailure');
        $plugin = $this->createPlugin($manager, $this->createMock(RetryRequestPublisher::class),
            $this->createMock(LoggerInterface::class));

        self::assertSame(95316064, $plugin->aroundGenerateAwb(new \stdClass(), fn () => 95316064, 125094));
    }

    private function createPlugin(
        AwbErrorLogManager $manager,
        RetryRequestPublisher $publisher,
        LoggerInterface $logger
    ): CourierGenerateAwbRetryPlugin {
        $repository = $this->createMock(AwbRepository::class);
        $repository->method('getById')->with(125094)->willReturn(new DataObject(['carrier_id' => 5]));

        return new CourierGenerateAwbRetryPlugin($repository, $manager, $publisher,
            $this->createMock(Config::class), $this->createMock(TransientFailureClassifier::class), $logger);
    }
}
