<?php

declare(strict_types=1);

namespace Ferienpass\AdminBundle\Tests\Components\Offer;

use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\AdminBundle\Components\Offer\OfferDateForm;
use Ferienpass\CoreBundle\Entity\Offer\OfferInterface;
use Ferienpass\CoreBundle\Entity\OfferDate;
use Ferienpass\CoreBundle\Entity\PageConfig;
use Ferienpass\CoreBundle\Settings\PageConfigManager;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

final class OfferDateFormTest extends TestCase
{
    public function testHydrateDateTimeWithInvalidStringReturnsNull(): void
    {
        $component = $this->makeComponent($this->createMock(EntityManagerInterface::class));

        self::assertNull($component->hydrateDateTime('202620-03-30T00:00'));
    }

    public function testHydrateDateThrowsNotFoundWhenIntIdResolvesToNull(): void
    {
        // Production race: admin A opens the date-edit modal; admin B (or
        // the same admin in another tab) deletes the date; admin A then
        // edits a field, which triggers Live Component re-hydration with
        // the now-stale int ID. Doctrine returns null; without this throw
        // the framework crashed with a TypeError trying to assign null to
        // the non-nullable `$date` LiveProp (Sentry issue 7377045821).
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->method('find')->with(OfferDate::class, 42)->willReturn(null);

        $component = $this->makeComponent($entityManager);

        $this->expectException(NotFoundHttpException::class);
        $component->hydrateDate(42);
    }

    public function testHydrateDateThrowsNotFoundWhenOfferIdResolvesToNull(): void
    {
        // "New OfferDate" form (date hasn't been persisted yet) carries the
        // parent offer's id as `{offer: <id>}`. If the offer itself gets
        // deleted between modal-open and re-hydration, return the same 404.
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->method('find')->with(OfferInterface::class, 99)->willReturn(null);

        $component = $this->makeComponent($entityManager);

        $this->expectException(NotFoundHttpException::class);
        $component->hydrateDate(['offer' => 99]);
    }

    public function testHydrateDateThrowsNotFoundOnUnknownShape(): void
    {
        // Tampered/garbled props shouldn't fall through to a TypeError on
        // null-assignment either — same 404 recovery path.
        $component = $this->makeComponent($this->createMock(EntityManagerInterface::class));

        $this->expectException(NotFoundHttpException::class);
        $component->hydrateDate('this is not a valid dehydrated shape');
    }

    public function testHydrateDateReturnsExistingDateWhenIntIdFound(): void
    {
        $date = $this->createMock(OfferDate::class);
        $entityManager = $this->createMock(EntityManagerInterface::class);
        $entityManager->method('find')->with(OfferDate::class, 7)->willReturn($date);

        $component = $this->makeComponent($entityManager);

        self::assertSame($date, $component->hydrateDate(7));
    }

    private function makeComponent(EntityManagerInterface $entityManager): OfferDateForm
    {
        $pageConfigManager = $this->createMock(PageConfigManager::class);
        $pageConfig = $this->createMock(PageConfig::class);
        $pageConfigManager->method('getPageConfig')->willReturn($pageConfig);
        $pageConfig->method('getTimezone')->willReturn('Europe/Berlin');

        $formFactory = $this->createMock(FormFactoryInterface::class);

        return new OfferDateForm($entityManager, $pageConfigManager, $formFactory);
    }
}
