<?php declare(strict_types=1);

namespace App\Engine\Admin;

final readonly class Paginator
{

    public const URL_PARAM = "_page";

    public function __construct(
        private \Symfony\Component\HttpFoundation\RequestStack $requestStack,
        private \Symfony\Component\Routing\RouterInterface     $router,
    ) {
    }

    public function createPagination(int $totalRecords, int $currentPage, int $pageSize = 25, int $displayedPages = 3, bool $showPreviousNextButtons = true): \App\Engine\Inertia\Admin\List\PaginationViewModel
    {

        $pages = $this->createPages($totalRecords, $currentPage, $pageSize, $displayedPages);

        $previousLink = $showPreviousNextButtons
            ? ($currentPage > 0 ? $this->generateUrlFromRequest($currentPage - 1) : "")
            : null;
        $nextLink = $showPreviousNextButtons
            ? ($currentPage < (ceil($totalRecords / $pageSize)) ? $this->generateUrlFromRequest($currentPage + 1) : "")
            : null;

        return new \App\Engine\Inertia\Admin\List\PaginationViewModel(
            pages:                   $pages,
            showPreviousNextButtons: $showPreviousNextButtons,
            previousLink:            $previousLink,
            nextLink:                $nextLink,
        );
    }

    private function createPages(int $totalRecords, int $currentPage, int $pageSize, int $displayedPages): array
    {
        $pages = [];
        $totalPages = (int)ceil($totalRecords / $pageSize);
        $inactivePages = min($displayedPages, $totalPages) - 1; // Odečteme active page

        $leftSide = (int)floor($inactivePages / 2);
        if ($leftSide >= $currentPage) {
            $leftSide = $currentPage - 1; // Pokud máme vlevo méně nebo stejně záznamů než kolik je před aktivní stránkou, tak vyjeme z aktivní stránky
        }
        $rightSide = $inactivePages - $leftSide; // Pravá strana je automaticky zbytek
        $diff = $totalPages - $currentPage;
        if ($rightSide > $diff) { // Pokud je zbývající počet stránek vpravo menší než předpokládaný, tak se rozdil přičte vlevo a vpravo se nastaví jen max možné množství tedy diff
            $leftSide += $rightSide - $diff;
            $rightSide = $diff;
        }

        $pageNumber = $currentPage - $leftSide - 1; // Korekce -1 aby bylo možné před přidání záznamů provést konzistentně inkrementaci
        for ($i = 0; $i < $leftSide; $i++) {
            $pageNumber += 1;
            $pages[] = new \App\Engine\Inertia\Admin\List\PaginationItemViewModel(
                number: $pageNumber,
                link:   $this->generateUrlFromRequest($pageNumber),
            );
        }
        $pageNumber += 1;
        $pages[] = new \App\Engine\Inertia\Admin\List\PaginationItemViewModel(
            number:   $pageNumber,
            link:     $this->generateUrlFromRequest($pageNumber),
            isActive: true,
        );
        for ($j = 0; $j < $rightSide; $j++) {
            $pageNumber += 1;
            $pages[] = new \App\Engine\Inertia\Admin\List\PaginationItemViewModel(
                number: $pageNumber,
                link:   $this->generateUrlFromRequest($pageNumber),
            );
        }

        return $pages;
    }

    private function generateUrlFromRequest(int $page): string
    {
        $request = $this->requestStack->getCurrentRequest();
        $requestParameters = $request->query->all();
        $requestParameters[self::URL_PARAM] = $page;

        return $this->router->generate(
            name:       $request->attributes->get("_route"),
            parameters: array_merge($request->attributes->get("_route_params"), $requestParameters),
        );
    }

    public function getCurrentPageFromRequest(): int
    {
        return (int)$this->requestStack->getCurrentRequest()->query->get(self::URL_PARAM, "1");
    }

}