<?php

namespace NoahVet\Reef\Test\A_Unit\Domain\Tool;

use NoahVet\Reef\Domain\Tool\StringTool;
use PHPUnit\Framework\TestCase;

final class StringToolTest extends TestCase
{
    private StringTool $subject;

    protected function setUp(): void
    {
        $this->subject = new StringTool();
    }

    public function testFromBurgerCaseToSnakeCase(): void
    {
        self::assertSame(
            'once_upon_a_time',
            $this->subject::fromBurgerCaseToSnakeCase('once-upon-a-time'),
        );
    }

    public function testFromBurgerCaseToSnakeCaseAlreadyInSnakeCase(): void
    {
        self::assertSame(
            'once_upon_a_time',
            $this->subject::fromBurgerCaseToSnakeCase('once_upon_a_time'),
        );
    }

    public function testFromSnakeCaseToBurgerCase(): void
    {
        self::assertSame(
            'once-upon-a-time',
            $this->subject::fromSnakeCaseToBurgerCase('once_upon_a_time'),
        );
    }

    public function testFromSnakeCaseToBurgerCaseAlreadyInBurgerCase(): void
    {
        self::assertSame(
            'once-upon-a-time',
            $this->subject::fromSnakeCaseToBurgerCase('once-upon-a-time'),
        );
    }

    public function testFromSnakeCaseToCamelCase(): void
    {
        self::assertSame(
            'onceUponATime',
            $this->subject::fromSnakeCaseToCamelCase('once_upon_a_time'),
        );
    }

    public function testFromSnakeCaseToCamelCaseWithUppercaseInput(): void
    {
        self::assertSame(
            'onceUponATime',
            $this->subject::fromSnakeCaseToCamelCase('ONCE_UPON_A_TIME'),
        );
    }

    public function testFromSnakeCaseToCamelCaseWithSpace(): void
    {
        self::assertSame(
            'onceUponATime',
            $this->subject::fromSnakeCaseToCamelCase(' ONCE_UPON_A_TIME '),
        );
    }

    public function testFromSpacedToBurgerCase(): void
    {
        self::assertSame(
            'once-upon-a-time',
            $this->subject::fromSpacedToBurgerCase('Once upon a time'),
        );
    }

    public function testFromSpacedToBurgerCaseAlreadyInSnakeCase(): void
    {
        self::assertSame(
            'once-upon-a-time',
            $this->subject::fromSpacedToBurgerCase('once-upon-a-time'),
        );
    }

    public function testFromSpacedToUpperBurgerCase(): void
    {
        self::assertSame(
            'ONCE-UPON-A-TIME',
            $this->subject::fromSpacedToUpperBurgerCase('Once upon a time'),
        );
    }

    public function testFromSpacedToUpperBurgerCaseAlreadyInSnakeCase(): void
    {
        self::assertSame(
            'ONCE-UPON-A-TIME',
            $this->subject::fromSpacedToUpperBurgerCase('ONCE-UPON-A-TIME'),
        );
    }

    public function testFromPascalCaseToCamelCase(): void
    {
        self::assertSame(
            'inPascalCase',
            $this->subject::fromPascalCaseToCamelCase('InPascalCase'),
        );
    }

    public function testFromPascalCaseToCamelCaseAlreadyInCamelCase(): void
    {
        self::assertSame(
            'alreadyInCamelCase',
            $this->subject::fromPascalCaseToCamelCase('alreadyInCamelCase'),
        );
    }

    public function testFromSpacedToPascalCase(): void
    {
        self::assertSame(
            'Once Upon A Time',
            $this->subject::fromSpacedToPascalCase('once upon a time'),
        );
    }

    public function testFromSpacedToPascalCaseAlreadyInPascalCase(): void
    {
        self::assertSame(
            'Once Upon A Time',
            $this->subject::fromSpacedToPascalCase('Once Upon A Time'),
        );
    }

    public function testFromSpacedToSnakeUpperCase(): void
    {
        self::assertSame(
            'ONCE_UPON_A_TIME',
            $this->subject::fromSpacedToSnakeUpperCase(' Once Upon A Time '),
        );
    }

    public function testFromSpacedToSnakeUpperCaseAlreadyInSnakeUpperCase(): void
    {
        self::assertSame(
            'ONCE_UPON_A_TIME',
            $this->subject::fromSpacedToSnakeUpperCase(' ONCE_UPON_A_TIME '),
        );
    }

    public function testToSnakeUpperCaseFromCamelCase(): void
    {
        self::assertSame(
            'ONCE_UPON_A_TIME',
            $this->subject::toSnakeUpperCase('onceUponATime'),
        );
    }

    public function testToSnakeUpperCaseFromBurgerCaseWithAcronym(): void
    {
        self::assertSame(
            'HTTP_RESPONSE_2_XX',
            $this->subject::toSnakeUpperCase('HTTPResponse2XX'),
        );
    }

    public function testToSnakeUpperCaseFromMixedSeparators(): void
    {
        self::assertSame(
            'ONCE_UPON_A_TIME',
            $this->subject::toSnakeUpperCase(' once-upon a time '),
        );
    }

    public function testToSnakeUpperCaseWithAccentAndSpaces(): void
    {
        self::assertSame(
            'HÉLLO_WORLD',
            $this->subject::toSnakeUpperCase('  héllo WORLD  '),
        );
    }

    public function testToSnakeUpperCaseWithSpecialCharacters(): void
    {
        self::assertSame(
            'FOO_BAR_BAZ',
            $this->subject::toSnakeUpperCase('foo@bar#baz'),
        );
    }

    public function testToSnakeUpperCaseAlreadySnakeCaseWithNoise(): void
    {
        self::assertSame(
            'ALREADY_SNAKE_CASE',
            $this->subject::toSnakeUpperCase('  already_snake_case  '),
        );
    }

    public function testToSnakeUpperCaseEmptyString(): void
    {
        self::assertSame(
            '',
            $this->subject::toSnakeUpperCase('   '),
        );
    }

    public function testToLowerCaseWithoutAccent(): void
    {
        self::assertSame(
            'aaaaaceeeeiiiinooooouuuuyaaaaaceeeeiiiinooooouuuuy',
            $this->subject::toLowerCaseWithoutAccent(' àáâãäçèéêëìíîïñòóôõöùúûüýÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ '),
        );
    }

    public function testToUpperCaseWithoutAccent(): void
    {
        self::assertSame(
            'AAAAACEEEEIIIINOOOOOUUUUYAAAAACEEEEIIIINOOOOOUUUUY',
            $this->subject::toUpperCaseWithoutAccent(' àáâãäçèéêëìíîïñòóôõöùúûüýÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ '),
        );
    }

    public function testRemoveAccent(): void
    {
        self::assertSame(
            'aaaaaceeeeiiiinooooouuuuyAAAAACEEEEIIIINOOOOOUUUUY',
            $this->subject::removeAccent(' àáâãäçèéêëìíîïñòóôõöùúûüýÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ '),
        );
    }

    public function testRemoveWhitespace(): void
    {
        self::assertSame(
            '',
            $this->subject::removeWhitespace(' '),
        );

        self::assertSame(
            '',
            $this->subject::removeWhitespace('  '),
        );

        self::assertSame(
            'aéz',
            $this->subject::removeWhitespace(' aéz '),
        );

        self::assertSame(
            'Aéz&-!)=',
            $this->subject::removeWhitespace(' A é z & - ! ) = '),
        );
    }

    public function testToName(): void
    {
        $names = [
            'aurelien' => 'Aurelien',
            ' Jean-Paul ' => 'Jean-Paul',
            'JeAN MaRie' => 'Jean Marie',
            'DE FUNES' => 'De Funes',
            'D\'Amico' => 'D\'Amico',
            ' ' => '',
            '' => '',
            '\'' => '\'',
        ];
        foreach ($names as $name => $expectedName) {
            self::assertSame(
                $expectedName,
                $this->subject::toName($name),
            );
        }
    }

    public function testToPascalCaseWithoutAccent(): void
    {
        self::assertSame(
            'OnceUponATime',
            $this->subject::toPascalCase(' onceUponATime '),
        );
    }

    public function testToPascalCaseWithAccent(): void
    {
        self::assertSame(
            'ÀBáâCãDä',
            $this->subject::toPascalCase(' àBáâCãDä '),
        );
    }

    public function testFromCamelCaseToBurgerCase(): void
    {
        self::assertSame(
            'a-A-báâ-cã-dä',
            $this->subject::fromCamelCaseToBurgerCase(' aABáâCãDä '),
        );
    }

    public function testFromCamelCaseToBurgerCaseWithDigits(): void
    {
        self::assertSame(
            'HTTP-response-2-XX',
            $this->subject::fromCamelCaseToBurgerCase('HTTPResponse2XX'),
        );
    }
}
