<?php

namespace App\Tests\A_Unit\Prestashop\Hook\DisplayOrderConfirmation1;

use Myvetshop\Module\Clinique\Adapter\ConfigurationAdapter;
use Myvetshop\Module\Clinique\Adapter\Repository\CartRepository;
use Myvetshop\Module\Clinique\Adapter\Repository\OrderRepository;
use Myvetshop\Module\Clinique\Prestashop\Hook\OrderStatusDisplayOrderConfirmation1Listener;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use PrestaShop\PrestaShop\Adapter\LegacyContext;
use Symfony\Component\HttpFoundation\Request;

class OrderStatusDisplayOrderConfirmation1ListenerTest extends TestCase
{
    /**
     * @var LegacyContext&MockObject
     */
    private LegacyContext $legacyContextMock;

    /**
     * @var \Smarty&MockObject
     */
    private \Smarty $smartyMock;

    /**
     * @var \Context&MockObject
     */
    private \Context $contextMock;

    /**
     * @var \Cart&MockObject
     */
    private \Cart $cartMock;

    /**
     * @var \Order&MockObject
     */
    private \Order $orderMock;

    /**
     * @var CartRepository&MockObject
     */
    private CartRepository $cartRepositoryMock;

    /**
     * @var ConfigurationAdapter&MockObject
     */
    private ConfigurationAdapter $configurationAdapterMock;

    /**
     * @var OrderRepository&MockObject
     */
    private OrderRepository $orderRepositoryMock;

    protected function setUp(): void
    {
        $this->legacyContextMock = $this->createMock(LegacyContext::class);
        $this->smartyMock = $this->createMock(\Smarty::class);
        $this->contextMock = $this->createMock(\Context::class);

        $this->contextMock->smarty = $this->smartyMock;

        $this->legacyContextMock
            ->method('getContext')
            ->willReturn($this->contextMock);

        $this->cartRepositoryMock = $this->createMock(CartRepository::class);
        $this->configurationAdapterMock = $this->createMock(ConfigurationAdapter::class);
        $this->orderRepositoryMock = $this->createMock(OrderRepository::class);
        $this->cartMock = $this->createMock(\Cart::class);
        $this->orderMock = $this->createMock(\Order::class);

        $this->configurationAdapterMock
            ->method('get')
            ->willReturnCallback(function (string $key) {
                switch ($key) {
                    case 'PS_OS_ERROR':
                        return 3;

                    case 'PS_OS_OUTOFSTOCK_UNPAID':
                        return 4;

                    default:
                        return false;
                }
            });
    }

    /**
     * Test case where the cart's secure key does not match.
     */
    public function testDisplayOrderConfirmation1ReturnsEmptyStringWhenCartNotFound(): void
    {
        $request = new Request();
        $request->query->set('id_cart', '1');
        new \Tools($request);

        $this->cartRepositoryMock
            ->method('findById')
            ->with(1)
            ->willReturn(null);

        $listener = new OrderStatusDisplayOrderConfirmation1Listener(
            $this->cartRepositoryMock,
            $this->configurationAdapterMock,
            $this->legacyContextMock,
            $this->orderRepositoryMock
        );

        $result = $listener->displayOrderConfirmation1();

        $this->assertEquals('', $result);
    }

    public function testDisplayOrderConfirmation1ReturnsEmptyStringWhenSecureKeyDoesNotMatch(): void
    {
        $request = new Request();
        $request->query->set('id_cart', '1');
        $request->query->set('key', 'wrong_key');
        new \Tools($request);

        $this->cartMock->secure_key = 'valid_key';

        $this->cartRepositoryMock
            ->method('findById')
            ->with(1)
            ->willReturn($this->cartMock);

        $listener = new OrderStatusDisplayOrderConfirmation1Listener(
            $this->cartRepositoryMock,
            $this->configurationAdapterMock,
            $this->legacyContextMock,
            $this->orderRepositoryMock
        );

        $result = $listener->displayOrderConfirmation1();

        $this->assertEquals('', $result);
    }

    /**
     * Test case where the order's state is success.
     */
    public function testDisplayOrderConfirmation1ReturnsSuccessTemplate(): void
    {
        $request = new Request();
        $request->query->set('id_cart', '1');
        $request->query->set('key', 'key');
        new \Tools($request);

        $this->cartMock->id = 1;
        $this->cartMock->secure_key = 'key';

        $this->cartRepositoryMock
            ->method('findById')
            ->with(1)
            ->willReturn($this->cartMock);

        $this->orderMock
            ->method('getCurrentOrderState')
            ->willReturn((object) ['id' => 2]);

        $this->orderRepositoryMock
            ->method('findByCartId')
            ->with(1)
            ->willReturn($this->orderMock);

        $this->smartyMock
            ->expects($this->once())
            ->method('assign')
            ->with(['orderStatus' => 'success']);

        $this->smartyMock
            ->expects($this->once())
            ->method('fetch')
            ->with('module:myvetshopclinique/views/templates/hook/display_order_confirmation1.tpl')
            ->willReturn('success_template');

        $listener = new OrderStatusDisplayOrderConfirmation1Listener(
            $this->cartRepositoryMock,
            $this->configurationAdapterMock,
            $this->legacyContextMock,
            $this->orderRepositoryMock
        );

        $result = $listener->displayOrderConfirmation1();

        $this->assertEquals('success_template', $result);
    }

    /**
     * Test case where the order's state is an error.
     */
    public function testDisplayOrderConfirmation1ReturnsErrorTemplate(): void
    {
        $request = new Request();
        $request->query->set('id_cart', '1');
        $request->query->set('key', 'key');
        new \Tools($request);

        $this->cartMock->id = 1;
        $this->cartMock->secure_key = 'key';

        $this->cartRepositoryMock
            ->method('findById')
            ->with(1)
            ->willReturn($this->cartMock);

        $this->orderMock
            ->method('getCurrentOrderState')
            ->willReturn((object) ['id' => 3]);

        $this->orderRepositoryMock
            ->method('findByCartId')
            ->with(1)
            ->willReturn($this->orderMock);

        $this->orderMock->method('getCurrentOrderState')->willReturn((object) ['id' => 3]);

        $this->smartyMock
            ->expects($this->once())
            ->method('assign')
            ->with(['orderStatus' => 'error'], null, false);

        $this->smartyMock
            ->expects($this->once())
            ->method('fetch')
            ->with('module:myvetshopclinique/views/templates/hook/display_order_confirmation1.tpl')
            ->willReturn('error_template');

        $listener = new OrderStatusDisplayOrderConfirmation1Listener(
            $this->cartRepositoryMock,
            $this->configurationAdapterMock,
            $this->legacyContextMock,
            $this->orderRepositoryMock
        );

        $result = $listener->displayOrderConfirmation1();

        $this->assertEquals('error_template', $result);
    }
}
