<?php

/**
 * @package     Dotclear
 * @subpackage  Backend
 *
 * @copyright   Olivier Meunier & Association Dotclear
 * @copyright   AGPL-3.0
 */
declare(strict_types=1);

namespace Dotclear\Core\Backend\Listing;

use Dotclear\Helper\Html\Form\Div;
use Dotclear\Helper\Html\Form\Form;
use Dotclear\Helper\Html\Form\Hidden;
use Dotclear\Helper\Html\Form\Img;
use Dotclear\Helper\Html\Form\Label;
use Dotclear\Helper\Html\Form\Li;
use Dotclear\Helper\Html\Form\Link;
use Dotclear\Helper\Html\Form\None;
use Dotclear\Helper\Html\Form\Number;
use Dotclear\Helper\Html\Form\Span;
use Dotclear\Helper\Html\Form\Strong;
use Dotclear\Helper\Html\Form\Submit;
use Dotclear\Helper\Html\Form\Ul;
use Dotclear\Helper\Html\Html;
use Dotclear\Helper\Html\Pager as HelperPager;

/**
 * @brief   List pager form helper.
 *
 * @since   2.20
 */
class Pager extends HelperPager
{
    /**
     * Form-handler URL.
     */
    protected string $form_action = '';

    /**
     * Form hidden fields.
     *
     * @var     array<Hidden>     $form_hidden
     */
    protected array $form_hidden = [];

    /**
     * Additional URL args
     *
     * @var     array<string, string>    $args
     */
    protected array $args = [];

    /**
     * Gets the link.
     *
     * @param   string            $li_class           The li class
     * @param   string            $href               The href
     * @param   string[]          $img_src            The images source (light, dark)
     * @param   string[]          $img_src_nolink     The image source nolink (light, dark)
     * @param   string            $img_alt            The image alternate
     * @param   bool              $enable_link        The enable link
     *
     * @return  Li  The link.
     */
    protected function getLink(string $li_class, string $href, array $img_src, array $img_src_nolink, string $img_alt, bool $enable_link): Li
    {
        if ($enable_link) {
            return (new Li())
                ->class(array_filter(['btn', $li_class]))
                ->items([
                    (new Link())
                        ->href($href)
                        ->items([
                            (new Img($img_src[0]))
                                ->class('light-only')
                                ->alt($img_alt),
                            (new Img($img_src[1]))
                                ->class('dark-only')
                                ->alt($img_alt),
                        ]),
                    (new Span($img_alt))
                        ->class('hidden'),
                ]);
        }

        return (new Li())
            ->class(array_filter(['btn', 'no-link', $li_class]))
            ->items([
                (new Img($img_src_nolink[0]))
                    ->class('light-only')
                    ->alt($img_alt),
                (new Img($img_src_nolink[1]))
                    ->class('dark-only')
                    ->alt($img_alt),
            ]);
    }

    /**
     * Sets the url.
     */
    protected function setURL(): void
    {
        parent::setURL();

        $request_uri = isset($_SERVER['REQUEST_URI']) && is_string($request_uri = $_SERVER['REQUEST_URI']) ? $request_uri : '';
        $url         = parse_url($request_uri);
        if (isset($url['query'])) {
            parse_str($url['query'], $args);
        } else {
            $args = [];
        }

        # Removing session information
        if (session_id() && session_name() !== false && isset($args[session_name()])) {
            unset($args[session_name()]);
        }

        if (isset($args[$this->var_page])) {
            unset($args[$this->var_page]);
        }

        if (isset($args['ok'])) {
            unset($args['ok']);
        }

        // Add additional args if any
        if ($this->args !== []) {
            $args = array_merge($args, $this->args);
        }

        foreach ($args as $k => $v) {
            // Check parameter key (will prevent some forms of XSS)
            if ($k === preg_replace('`[^A-Za-z0-9_-]`', '', (string) $k)) {
                if (is_array($v)) {
                    foreach ($v as $v2) {
                        $value = is_scalar($v2) ? (string) $v2 : '';

                        $this->form_hidden[] = (new Hidden([$k . '[]'], Html::escapeHTML($value)));
                    }
                } else {
                    $this->form_hidden[] = (new Hidden([$k], Html::escapeHTML($v)));
                }
            }
        }

        $this->form_action = $url['path'] ?? '';
    }

    /**
     * Set additional URL args
     *
     * @param array<string, string> $args Additional args for URL
     */
    public function setArgs(array $args = []): void
    {
        $this->args = $args;
    }

    /**
     * Pager Links.
     *
     * @return  string  The pager links
     */
    public function getLinks(): string
    {
        $this->setURL();

        if ($this->nb_elements === 0) {
            return '';
        }

        // Add additional args if any
        $url = $this->page_url;
        if ($url && $this->args !== []) {
            foreach ($this->args as $k => $v) {
                if (preg_match('/[\?]/', $url)) {
                    $url .= '&' . $k . '=' . Html::escapeHTML($v);
                } else {
                    $url .= '?' . $k . '=' . Html::escapeHTML($v);
                }
            }
        }

        $htmlFirst = $this->getLink(
            'first',
            sprintf((string) $url, 1),
            ['images/pagination/first.svg', 'images/pagination/first-dark.svg'],
            ['images/pagination/no-first.svg', 'images/pagination/no-first-dark.svg'],
            __('First page'),
            ($this->env > 1)
        );
        $htmlPrev = $this->getLink(
            'prev',
            sprintf((string) $url, $this->env - 1),
            ['images/pagination/previous.svg', 'images/pagination/previous-dark.svg'],
            ['images/pagination/no-previous.svg', 'images/pagination/no-previous-dark.svg'],
            __('Previous page'),
            ($this->env > 1)
        );
        $htmlNext = $this->getLink(
            'next',
            sprintf((string) $url, $this->env + 1),
            ['images/pagination/next.svg', 'images/pagination/next-dark.svg'],
            ['images/pagination/no-next.svg', 'images/pagination/no-next-dark.svg'],
            __('Next page'),
            ($this->env < $this->nb_pages)
        );
        $htmlLast = $this->getLink(
            'last',
            sprintf((string) $url, $this->nb_pages),
            ['images/pagination/last.svg', 'images/pagination/last-dark.svg'],
            ['images/pagination/no-last.svg', 'images/pagination/no-last-dark.svg'],
            __('Last page'),
            ($this->env < $this->nb_pages)
        );

        $htmlCurrent = (new Li())
            ->class('active')
            ->items([
                (new Strong(sprintf(__('Page %1$s / %2$s'), $this->env, $this->nb_pages))),
            ]);

        $htmlDirect = $this->nb_pages > 1 ?
        (new Li())
            ->class('direct-access')
            ->items([
                (new Number([$this->var_page], 1, $this->nb_pages, $this->env))
                    ->label((new Label(__('Direct access page:')))->class('classic')),
                (new Submit(['ok'], __('ok')))
                    ->class('reset'),
            ]) :
        (new None());

        return (new Form(['pager']))
            ->method('get')
            ->action($this->form_action)
            ->fields([
                (new Div())
                    ->class('pager')
                    ->items([
                        (new Ul())
                            ->items([
                                $htmlFirst,
                                $htmlPrev,
                                $htmlCurrent,
                                $htmlNext,
                                $htmlLast,
                                $htmlDirect,
                            ]),
                    ]),
                ...$this->form_hidden,
            ])
        ->render();
    }
}
