<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Tests\Application;

use Ferienpass\CoreBundle\Application\ExtraQuestion;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

class ExtraQuestionTest extends TestCase
{
    #[DataProvider('typeProvider')]
    public function testCoercesTypeToASupportedOne(mixed $input, string $expected): void
    {
        self::assertSame($expected, ExtraQuestion::type($input));
    }

    public static function typeProvider(): iterable
    {
        yield 'known type' => ['yn', 'yn'];
        yield 'file' => ['file', 'file'];
        yield 'unknown falls back to free text' => ['bogus', 'txt'];
        yield 'null falls back to free text' => [null, 'txt'];
        yield 'non-string falls back to free text' => [42, 'txt'];
    }

    #[DataProvider('kindsProvider')]
    public function testNormalisesTheAllowedKinds(mixed $input, array $expected): void
    {
        self::assertSame($expected, ExtraQuestion::kinds($input));
    }

    public static function kindsProvider(): iterable
    {
        yield 'both' => [['image', 'pdf'], ['image', 'pdf']];
        yield 'one' => [['pdf'], ['pdf']];
        // A question that accepts nothing could never be answered, so an empty or
        // unrecognised selection opens up to everything we support.
        yield 'empty means everything' => [[], ['image', 'pdf']];
        yield 'unknown means everything' => [['exe'], ['image', 'pdf']];
        yield 'null means everything' => [null, ['image', 'pdf']];
        yield 'order is canonical, not as given' => [['pdf', 'image'], ['image', 'pdf']];
        yield 'duplicates collapse' => [['pdf', 'pdf'], ['pdf']];
    }

    public function testImageExtensionsIncludeHeicForIphoneUploads(): void
    {
        $extensions = ExtraQuestion::extensions(['image']);

        self::assertContains('heic', $extensions);
        self::assertContains('jpg', $extensions);
        self::assertNotContains('pdf', $extensions);
    }

    public function testExtensionsOfBothKindsAreMergedWithoutDuplicates(): void
    {
        $extensions = ExtraQuestion::extensions(['image', 'pdf']);

        self::assertContains('pdf', $extensions);
        self::assertSame(array_values(array_unique($extensions)), $extensions);
    }

    public function testAcceptUsesTheWildcardForImagesSoPhonesOfferTheCamera(): void
    {
        self::assertSame('image/*,application/pdf', ExtraQuestion::accept(['image', 'pdf']));
        self::assertSame('image/*', ExtraQuestion::accept(['image']));
        self::assertSame('application/pdf', ExtraQuestion::accept(['pdf']));
    }

    public function testUrlIdIsBase58AndRoundTripsBackToTheStoredForm(): void
    {
        $stored = '0192d1f0-0000-7000-8000-000000000001';
        $urlId = ExtraQuestion::urlId($stored);

        // base58, like every other id in the admin URLs — no dashes, no hex form.
        self::assertMatchesRegularExpression('/^[1-9A-HJ-NP-Za-km-z]{22}$/', $urlId);
        self::assertSame($stored, ExtraQuestion::fromUrlId($urlId));
    }

    public function testFromUrlIdStillAcceptsTheRfcFormOfOlderLinks(): void
    {
        $stored = '0192d1f0-0000-7000-8000-000000000001';

        self::assertSame($stored, ExtraQuestion::fromUrlId($stored));
    }

    public function testALegacyNonUuidQuestionIdTravelsUnchanged(): void
    {
        // Questions predating the uuid normalisation carry arbitrary ids; those must
        // keep generating (and resolving) a URL rather than blowing up.
        self::assertSame('test-id-1234', ExtraQuestion::urlId('test-id-1234'));
        self::assertSame('test-id-1234', ExtraQuestion::fromUrlId('test-id-1234'));
    }

    public function testAllowsImages(): void
    {
        self::assertTrue(ExtraQuestion::allowsImages(['image']));
        self::assertFalse(ExtraQuestion::allowsImages(['pdf']));
        // No restriction stored → everything, images included.
        self::assertTrue(ExtraQuestion::allowsImages([]));
    }
}
