<?php

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

use NoahVet\Reef\Domain\Tool\DateTool;
use NoahVet\Reef\Domain\Tool\DateToolInterface;
use PHPUnit\Framework\TestCase;

final class DateToolTest extends TestCase
{
    private DateToolInterface $subject;

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

    public function testFromNullableStringToDateTime(): void
    {
        $dateTime = new \DateTime('2022-12-31T00:00:00+00:00');

        $result = $this->subject::fromNullableStringToDateTime(
            '2022-12-31T00:00:00+00:00',
        );

        self::assertEquals(
            $dateTime,
            $result,
        );
    }

    public function testFromNullableStringToDateTimeWhenDateIsEqualsToNull(): void
    {
        self::assertNull(
            $this->subject::fromNullableStringToDateTime(null),
        );
    }

    public function testToFirstSecondOfTheDayWithNegativeUTC(): void
    {
        $dateTime = new \DateTime('2021-12-31T00:00:00-02:00');
        $this->subject::toFirstSecondOfTheDay($dateTime);

        self::assertSame(
            '2021-12-31T00:00:00-02:00',
            $dateTime->format(\DATE_ATOM),
        );
    }

    public function testToFirstSecondOfTheDayWithPositiveUTC(): void
    {
        $dateTime = new \DateTime('2021-12-31T00:00:00+02:00');
        $this->subject::toFirstSecondOfTheDay($dateTime);

        self::assertSame(
            '2021-12-31T00:00:00+02:00',
            $dateTime->format(\DATE_ATOM),
        );
    }

    public function testToFirstSecondOfTheDayWithUTCZero(): void
    {
        $dateTime = new \DateTime('2022-12-31T00:00:00+00:00');
        $this->subject::toFirstSecondOfTheDay($dateTime);

        self::assertSame(
            '2022-12-31T00:00:00+00:00',
            $dateTime->format(\DATE_ATOM),
        );
    }

    public function testIsFirstDayOfTheMonthWithUTCZero(): void
    {
        $dateTime = new \DateTime('2022-12-01T00:00:00+00:00');
        $result = $this->subject::IsFirstDayOfTheMonth($dateTime);

        self::assertTrue(
            $result,
        );

        $dateTime = new \DateTime('2022-12-02T00:00:00+00:00');
        $result = $this->subject::IsFirstDayOfTheMonth($dateTime);

        self::assertFalse(
            $result,
        );
    }

    public function testToLastSecondOfTheDayWithNegativeUTC(): void
    {
        $dateTime = new \DateTime('2021-12-31T00:00:00-02:00');
        $this->subject::toLastSecondOfTheDay($dateTime);

        self::assertSame(
            '2021-12-31T23:59:59-02:00',
            $dateTime->format(\DATE_ATOM),
        );
    }

    public function testToLastSecondOfTheDayWithPositiveUTC(): void
    {
        $dateTime = new \DateTime('2021-12-31T00:00:00+02:00');
        $this->subject::toLastSecondOfTheDay($dateTime);

        self::assertSame(
            '2021-12-31T23:59:59+02:00',
            $dateTime->format(\DATE_ATOM),
        );
    }

    public function testToLastSecondOfTheDayWithUTCZero(): void
    {
        $dateTime = new \DateTime('2022-12-31T00:00:00+00:00');
        $this->subject::toLastSecondOfTheDay($dateTime);

        self::assertSame(
            '2022-12-31T23:59:59+00:00',
            $dateTime->format(\DATE_ATOM),
        );
    }

    public function testToFirstSecondOfTheMonthWithUTCZero(): void
    {
        $dateTime = new \DateTime('2022-12-31T23:59:59+00:00');
        $this->subject::ToFirstSecondOfTheMonth($dateTime);

        self::assertSame(
            '2022-12-01T00:00:00+00:00',
            $dateTime->format(\DATE_ATOM),
        );
    }

    public function testFromStringToDateTimeNotImmutable(): void
    {
        $dateTime = new \DateTime('2022-12-31T00:00:00+00:00');

        $result = $this->subject::fromStringToDateTime(
            '2022-12-31T00:00:00+00:00',
            \DateTimeInterface::ATOM,
            $this->subject::UTC,
            false,
        );

        self::assertEquals(
            $dateTime,
            $result,
        );
    }

    public function testFromStringToDateTimeWhenDateStringIsNotADate(): void
    {
        $this->expectException(\LogicException::class);
        $this->expectExceptionMessage('The $dateString parameter is not in '.\DateTimeInterface::ATOM.' format.');
        $this->subject::fromStringToDateTime('bad');
    }

    public function testToLastSecondOfTheMonth(): void
    {
        $dateTime = new \DateTime('2020-12-31T23:59:59+00:00');

        $result = $this->subject::ToLastSecondOfTheMonth(
            new \DateTime('2020-12-31T00:00:00+00:00'),
        );

        self::assertEquals(
            $dateTime,
            $result,
        );
    }

    public function testToLastSecondOfThePreviousMonthWhenDateTimeIsMarch(): void
    {
        $dateTime = new \DateTime('2020-02-29T23:59:59+00:00');

        $result = $this->subject::ToLastSecondOfThePreviousMonth(
            new \DateTime('2020-03-31T00:00:00+00:00'),
        );

        self::assertEquals(
            $dateTime,
            $result,
        );
    }

    public function testIsDateWhenTheDateIsCorrect(): void
    {
        $result = $this->subject::isDate(
            '2020-02-29T23:59:59+00:00',
            \DateTimeInterface::ATOM,
        );

        self::assertTrue($result);

        $result = $this->subject::isDate(
            '2020-02-29',
            'Y-m-d',
        );

        self::assertTrue($result);
    }

    public function testIsDateWhenTheDateIsInAnotherDateFormat(): void
    {
        $result = $this->subject::isDate(
            '2020-02-29T23:59:59+00:00',
            'Y-m-d',
        );

        self::assertFalse($result);
    }

    public function testIsDateWhenTheFormatIsBad(): void
    {
        $result = $this->subject::isDate(
            '2020-02-29T23:59:59+00:00',
            'Y-m-d54',
        );

        self::assertFalse($result);
    }
}
