<?php

use KupShop\KupShopBundle\Pager\PagerExtraItem;

class PagerTest extends DatabaseTestCase
{
    /** @dataProvider data_testPagerWithExtraItems */
    public function testPagerWithExtraItems(array $pagerSettings, ?array $extraItems, int $expectedPagesCount, int $expectedTotalWithExtraItems, array $expectedPagerSpecFromAndLimit): void
    {
        $pager = new Pager();

        foreach ($extraItems ?: [] as $extraItem) {
            $pager->addExtraItems(new PagerExtraItem($extraItem[0], $extraItem[1] ?? null));
        }

        $pager->setPageNumber($pagerSettings[2]);
        $pager->setOnPage($pagerSettings[0]);
        $pager->setTotal($pagerSettings[1]);

        $this->assertEquals($expectedPagesCount, $pager->count);
        $this->assertEquals($pagerSettings[2], $pager->number);
        $this->assertEquals($expectedTotalWithExtraItems, $pager->totalWithExtraItems);

        $qb = sqlQueryBuilder()->andWhere($pager->getSpec());

        [$expectedFrom, $expectedLimit] = $expectedPagerSpecFromAndLimit;

        $this->assertEquals($expectedFrom, $qb->getFirstResult(), 'Assert OFFSET set by pager `getSpec` method');
        $this->assertEquals($expectedLimit, $qb->getMaxResults(), 'Assert LIMIT set by pager `getSpec` method');
    }

    public function data_testPagerWithExtraItems(): iterable
    {
        yield 'Page 1 active, 19/5=4 pages in total, 2 extra items on 1 page, 1 extra item on each next page, so 6 extra items in total, so one page is created by extra items' => [[5, 19, 1], [[1, 1], [1, null]], 5, 25, [0, 3]];
        yield 'Page 2 active, 19/5=4 pages in total, 2 extra items on 1 page, 1 extra item on each next page, so 6 extra items in total, so one page is created by extra items' => [[5, 19, 2], [[1, 1], [1, null]], 5, 25, [3, 4]];

        yield 'Page 1 active, 15/5=4 pages in total, 0 extra item on 1 page, 1 extra item on each next page until max 3, so 4 extra items in total, so one page is created by extra items' => [[5, 15, 1], [[1, 3]], 4, 18, [0, 4]];
        yield 'Page 2 active, 15/5=4 pages in total, 0 extra item on 1 page, 1 extra item on each next page until max 3, so 4 extra items in total, so one page is created by extra items' => [[5, 15, 2], [[1, 3]], 4, 18, [4, 4]];

        yield 'Page 1 active, 10/4=3 pages in total, 1 extra item on 1 page, 0 extra items on each next page, so one item is added in total and no next page is created' => [[4, 10, 1], [[1, 1]], 3, 11, [0, 3]];
        yield 'Page 2 active, 10/4=3 pages in total, 1 extra item on 1 page, 0 extra items on each next page, so one item is added in total and no next page is created' => [[4, 10, 2], [[1, 1]], 3, 11, [3, 4]];
        yield 'Page 3 active, 10/4=3 pages in total, 1 extra item on 1 page, 0 extra items on each next page, so one item is added in total and no next page is created' => [[4, 10, 3], [[1, 1]], 3, 11, [7, 4]];

        yield 'Page 1 active, pager without extra items 15/5=3' => [[5, 15, 1], null, 3, 15, [0, 5]];
        yield 'Page 2 active, pager without extra items 15/5=3' => [[5, 15, 2], null, 3, 15, [5, 5]];
    }

    /**
     * @dataProvider data_testPager
     */
    public function testPager(array $settings, array $expected)
    {
        $pager = new Pager();
        $pager->setPageInside($settings[0]);
        $pager->setPageSide($settings[1]);
        $pager->setOnPage($settings[2]);
        $pager->setPageNumber($settings[3]);
        $pager->setTotal($settings[4]);

        $this->assertEquals($expected[0], $pager->from());
        $this->assertEquals($expected[1], $pager->to());
        $this->assertEquals($expected[2], $pager->first());
        $this->assertEquals($expected[3], $pager->last());
        $this->assertEquals($expected[4], $pager->insidePagesFrom());
        $this->assertEquals($expected[5], $pager->insidePagesTo());
        $this->assertEquals($expected[6], $pager->firstDots());
        $this->assertEquals($expected[7], $pager->lastDots());
    }

    /*
     * $settings
     * pageInside = number of pages close between selected page and ...
     * pageSide = number of pages from start to ... and from ... to the end
     * onPage = number of records on the page
     * pageNumber = selected page
     * total = number of all records
     * */
    public function data_testPager()
    {
        return [
            [[5, 1, 2, 1, 15], [0, 1,    0, 1,  1, 6,  0, 1]],   // 1 2 3 4 5 6 ... 8   1 page
            [[5, 1, 2, 2, 15], [2, 3,    0, 1,  1, 7,  0, 0]],   // 1 2 3 4 5 6 7 8     2 page
            [[5, 1, 2, 5, 15], [8, 9,    0, 0,  1, 8,  0, 0]],   // 1 2 3 4 5 6 7 8     5 page
            [[5, 1, 2, 7, 15], [12, 13,  1, 0,  2, 8,  0, 0]],   // 1 2 3 4 5 6 7 8     7 page
            [[5, 1, 2, 8, 15], [14, 15,  1, 0,  3, 8,  1, 0]],   // 1 ... 3 4 5 6 7 8   8 page

            [[3, 1, 2, 1, 15], [0, 1,    0, 1,  1, 4,  0, 1]],   // 1 2 3 4 ... 8       1 page
            [[3, 1, 2, 2, 15], [2, 3,    0, 1,  1, 5,  0, 1]],   // 1 2 3 4 5 ... 8     2 page
            [[3, 1, 2, 5, 15], [8, 9,    1, 0,  2, 8,  0, 0]],   // 1 2 3 4 5 6 7 8     5 page
            [[3, 1, 2, 7, 15], [12, 13,  1, 0,  4, 8,  1, 0]],   // 1 ... 4 5 6 7 8     7 page
            [[3, 1, 2, 8, 15], [14, 15,  1, 0,  5, 8,  1, 0]],   // 1 ... 5 6 7 8       8 page

            [[2, 1, 2, 1, 15], [0, 1,    0, 1,  1, 3,  0, 1]],   // 1 2 3 ... 8         1 page
            [[2, 1, 2, 2, 15], [2, 3,    0, 1,  1, 4,  0, 1]],   // 1 2 3 4 ... 8       2 page
            [[2, 1, 2, 3, 15], [4, 5,    0, 1,  1, 5,  0, 1]],   // 1 2 3 4 5 ... 8     3 page
            [[2, 1, 2, 4, 15], [6, 7,    1, 1,  2, 6,  0, 1]],   // 1 2 3 4 5 6 ... 8   4 page
            [[2, 1, 2, 5, 15], [8, 9,    1, 1,  3, 7,  1, 0]],   // 1 ... 3 4 5 6 7 8   5 page
            [[2, 1, 2, 6, 15], [10, 11,  1, 0,  4, 8,  1, 0]],   // 1 ... 4 5 6 7 8     6 page
            [[2, 1, 2, 7, 15], [12, 13,  1, 0,  5, 8,  1, 0]],   // 1 ... 5 6 7 8       7 page
            [[2, 1, 2, 8, 15], [14, 15,  1, 0,  6, 8,  1, 0]],   // 1 ... 6 7 8         8 page
        ];
    }
}
