<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Tests\Util;

use Chill\MainBundle\Util\DateRangeCovering;
use PHPUnit\Framework\TestCase;

/**
 * @internal
 *
 * @coversNothing
 */
final class DateRangeCoveringTest extends TestCase
{
    public function testCoveringWithMinCover1()
    {
        $cover = new DateRangeCovering(1, new \DateTimeZone('Europe/Brussels'));
        $cover
            ->add(new \DateTime('2010-01-01'), new \DateTime('2010-12-01'), 1)
            ->add(new \DateTime('2010-06-01'), new \DateTime('2011-06-01'), 2)
            ->add(new \DateTime('2019-06-01'), new \DateTime('2019-06-01'), 3)
            ->compute();

        $this->assertTrue($cover->hasIntersections());
        $this->assertIsArray($cover->getIntersections());
        $this->assertCount(1, $cover->getIntersections());
        $this->assertEquals(
            new \DateTime('2010-06-01'),
            $cover->getIntersections()[0][0],
            'assert date start are the intersection'
        );
        $this->assertEquals(
            new \DateTime('2010-12-01'),
            $cover->getIntersections()[0][1],
            'assert date end are the intersection'
        );
        $this->assertIsArray($cover->getIntersections()[0][2]);
        $this->assertContains(1, $cover->getIntersections()[0][2]);
        $this->assertContains(2, $cover->getIntersections()[0][2]);
        $this->assertNotContains(3, $cover->getIntersections()[0][2]);
    }

    public function testCoveringWithMinCover1NoCoveringWithNullDates()
    {
        $cover = new DateRangeCovering(1, new \DateTimeZone('Europe/Brussels'));
        $cover
            ->add(new \DateTime('2021-10-05'), new \DateTime('2021-10-18'), 521)
            ->add(new \DateTime('2021-10-26'), null, 663)
            ->compute();

        $this->assertFalse($cover->hasIntersections());
    }

    public function testCoveringWithMinCover1WithTwoIntersections()
    {
        $cover = new DateRangeCovering(1, new \DateTimeZone('Europe/Brussels'));
        $cover
            ->add(new \DateTime('2010-01-01'), new \DateTime('2010-12-01'), 1)
            ->add(new \DateTime('2010-06-01'), new \DateTime('2011-06-01'), 2)
            ->add(new \DateTime('2019-01-01'), new \DateTime('2019-12-01'), 3)
            ->add(new \DateTime('2019-06-01'), new \DateTime('2020-06-01'), 4)
            ->compute();

        $this->assertTrue($cover->hasIntersections());
        $this->assertIsArray($cover->getIntersections());
        $this->assertCount(2, $cover->getIntersections());

        $intersections = $cover->getIntersections();

        // sort the intersections to compare them in expected order
        \usort($intersections, static function ($a, $b) {
            if ($a[0] === $b[0]) {
                return $a[1] <=> $b[1];
            }

            return $a[0] <=> $b[0];
        });

        // first intersection
        $this->assertEquals(
            new \DateTime('2010-06-01'),
            $intersections[0][0],
            'assert date start are the intersection'
        );
        $this->assertEquals(
            new \DateTime('2010-12-01'),
            $intersections[0][1],
            'assert date end are the intersection'
        );
        $this->assertIsArray($intersections[0][2]);
        $this->assertContains(1, $intersections[0][2]);
        $this->assertContains(2, $intersections[0][2]);
        $this->assertNotContains(3, $intersections[0][2]);
        $this->assertNotContains(4, $intersections[0][2]);

        // second intersection
        $this->assertEquals(
            new \DateTime('2019-06-01'),
            $intersections[1][0],
            'assert date start are the intersection'
        );
        $this->assertEquals(
            new \DateTime('2019-12-01'),
            $intersections[1][1],
            'assert date end are the intersection'
        );
        $this->assertIsArray($intersections[1][2]);
        $this->assertContains(3, $intersections[1][2]);
        $this->assertContains(4, $intersections[1][2]);
        $this->assertNotContains(1, $intersections[1][2]);
        $this->assertNotContains(2, $intersections[1][2]);
    }

    public function testCoveringWithMinCover2()
    {
        $cover = new DateRangeCovering(2, new \DateTimeZone('Europe/Brussels'));
        $cover
            ->add(new \DateTime('2010-01-01'), new \DateTime('2010-10-01'), 1)
            ->add(new \DateTime('2010-06-01'), new \DateTime('2010-09-01'), 2)
            ->add(new \DateTime('2010-04-01'), new \DateTime('2010-12-01'), 3)
            ->add(new \DateTime('2019-01-01'), new \DateTime('2019-10-01'), 4)
            ->add(new \DateTime('2019-06-01'), new \DateTime('2019-09-01'), 5)
            ->compute();
        $this->assertTrue($cover->hasIntersections());
        $this->assertIsArray($cover->getIntersections());
        $this->assertCount(1, $cover->getIntersections());

        $this->assertEquals(
            new \DateTime('2010-06-01'),
            $cover->getIntersections()[0][0],
            'assert date start are the intersection'
        );
        $this->assertEquals(
            new \DateTime('2010-09-01'),
            $cover->getIntersections()[0][1],
            'assert date end are the intersection'
        );
        $this->assertIsArray($cover->getIntersections()[0][2]);
        $this->assertContains(1, $cover->getIntersections()[0][2]);
        $this->assertContains(2, $cover->getIntersections()[0][2]);
        $this->assertContains(3, $cover->getIntersections()[0][2]);
        $this->assertNotContains(4, $cover->getIntersections()[0][2]);
        $this->assertNotContains(5, $cover->getIntersections()[0][2]);
    }

    public function testCoveringWithMinCover2AndThreePeriodsCovering()
    {
        $cover = new DateRangeCovering(2, new \DateTimeZone('Europe/Brussels'));
        $cover
            ->add(new \DateTime('2010-01-01'), new \DateTime('2010-10-01'), 1)
            ->add(new \DateTime('2010-06-01'), new \DateTime('2010-09-01'), 2)
            ->add(new \DateTime('2010-04-01'), new \DateTime('2010-12-01'), 3)
            ->add(new \DateTime('2009-01-01'), new \DateTime('2010-09-15'), 4)
            ->add(new \DateTime('2019-01-01'), new \DateTime('2019-10-01'), 5)
            ->add(new \DateTime('2019-06-01'), new \DateTime('2019-09-01'), 6)
            ->compute();

        $this->assertTrue($cover->hasIntersections());
        $this->assertIsArray($cover->getIntersections());
        $this->assertCount(1, $cover->getIntersections());

        $this->assertEquals(
            new \DateTime('2010-04-01'),
            $cover->getIntersections()[0][0],
            'assert date start are the intersection'
        );
        $this->assertEquals(
            new \DateTime('2010-09-15'),
            $cover->getIntersections()[0][1],
            'assert date end are the intersection'
        );
        $this->assertIsArray($cover->getIntersections()[0][2]);
        $this->assertContains(1, $cover->getIntersections()[0][2]);
        $this->assertContains(2, $cover->getIntersections()[0][2]);
        $this->assertContains(3, $cover->getIntersections()[0][2]);
        $this->assertContains(4, $cover->getIntersections()[0][2]);
        $this->assertNotContains(5, $cover->getIntersections()[0][2]);
        $this->assertNotContains(6, $cover->getIntersections()[0][2]);
    }

    public function testCoveringWithMinCover2AndThreePeriodsCoveringWithNullMetadata()
    {
        $cover = new DateRangeCovering(2, new \DateTimeZone('Europe/Brussels'));
        $cover
            ->add(new \DateTime('2010-01-01'), new \DateTime('2010-10-01'), null)
            ->add(new \DateTime('2010-06-01'), new \DateTime('2010-09-01'), null)
            ->add(new \DateTime('2010-04-01'), new \DateTime('2010-12-01'), null)
            ->add(new \DateTime('2009-01-01'), new \DateTime('2010-09-15'), null)
            ->add(new \DateTime('2019-01-01'), new \DateTime('2019-10-01'), null)
            ->add(new \DateTime('2019-06-01'), new \DateTime('2019-09-01'), null)
            ->compute();

        $this->assertTrue($cover->hasIntersections());
        $this->assertIsArray($cover->getIntersections());
        $this->assertCount(1, $cover->getIntersections());

        $this->assertEquals(
            new \DateTime('2010-04-01'),
            $cover->getIntersections()[0][0],
            'assert date start are the intersection'
        );
        $this->assertEquals(
            new \DateTime('2010-09-15'),
            $cover->getIntersections()[0][1],
            'assert date end are the intersection'
        );
        $this->assertIsArray($cover->getIntersections()[0][2]);
    }

    public function testCoveringWithMinCover3Absent()
    {
        $cover = new DateRangeCovering(3, new \DateTimeZone('Europe/Brussels'));
        $cover
            ->add(new \DateTime('2010-01-01'), new \DateTime('2010-10-01'), 1)
            ->add(new \DateTime('2010-06-01'), new \DateTime('2010-09-01'), 2)
            ->add(new \DateTime('2010-04-01'), new \DateTime('2010-12-01'), 3)
            ->add(new \DateTime('2019-01-01'), new \DateTime('2019-10-01'), 4)
            ->add(new \DateTime('2019-06-01'), new \DateTime('2019-09-01'), 5)
            ->compute();
        $this->assertFalse($cover->hasIntersections());
        $this->assertIsArray($cover->getIntersections());
        $this->assertCount(0, $cover->getIntersections());
    }
}
