<?php

    //todo DOCUMENTATION NEEDED

    declare(strict_types=1);

    namespace Icing\View\Helper;

    use Cake\Datasource\EntityInterface;
    use Cake\Utility\Hash;
    use Cake\Utility\Inflector;
    use Cake\View\Helper;
    use Cake\View\StringTemplateTrait;

    /**
     * PageActions helper
     *
     * @method PageActionsHelper add($button, $group = null)
     * @method PageActionsHelper link($title, $url = null, $options = [], $group = null)
     * @method PageActionsHelper cancel($title = 'Cancel', $url = ['action' => 'index'], $options = ['class' => 'btn btn-secondary'], $group = null)
     * @method PageActionsHelper submit($text = '<i class="fa fa-save fa-fw me-3"></i> Save', $options = ['class' => 'btn btn-success'], $group = null)
     * @method PageActionsHelper delete($title, $url = [], $options = [], $group = null)
     * @method PageActionsHelper postLink($title, $url = null, $options = [], $group = null)
     * @method PageActionsHelper separator()
     *
     * @property FormHelper $Form
     * @property HtmlHelper $Html
     */
    class PageActionsHelper extends Helper
    {
        use StringTemplateTrait;

        protected array $helpers = ['Icing.Form', 'Icing.Html'];

        protected array $buttons = [];

        /**
         * Default configuration.
         *
         * @var array<string, mixed>
         */
        protected array $_defaultConfig = [
            'defaultGroup' => 'default',
            'templates'    => [
                'default'        => '{{actions}}',
                'top-left.2'     => '{{dropdown}}',
                'top-right.2'    => '{{dropdown_right}}',
                'bottom-left.2'  => '{{dropup}}',
                'bottom-right.2' => '{{dropup_right}}',

                'dropdown_left'  => '
					<div class="btn-group">
                        <button
                            type="button"
                            class="btn btn-secondary border-light rounded"
                            data-bs-toggle="dropdown"
                            aria-expanded="false"
                        >
                            <span class="pe-4">Actions</span>
                            <i class="fa-solid fa-bars me-3 fa-lg"></i>
                            <span class="visually-hidden">Toggle Dropdown</span>
                        </button>
						<div class="dropdown-menu" style="width: max-content; max-width: 90vw;">
							<div class="d-flex flex-column mw-100 w-100 !px-3 !gap-2">
								{{actions}}
							</div>
						</div>
					</div>
				',
                'dropdown_right' => '
					<div class="btn-group">
                        <button
                            type="button"
                            class="btn btn-secondary border-light rounded"
                            data-bs-toggle="dropdown"
                            aria-expanded="false"
                        >
                            <span class="pe-4 d-none d-sm-inline">Actions</span>
                            <i class="fa-solid fa-bars fa-lg"></i>
                            <span class="visually-hidden">Toggle Dropdown</span>
                        </button>
						<div class="dropdown-menu dropdown-menu-end page-actions-dropdown-menu" style="width: max-content; max-width: 90vw;">
							<div class="d-flex flex-column mw-100 w-100 !px-3 !gap-2">
								{{actions}}
							</div>
						</div>
					</div>
				',
                'dropup_left'    => '
					<div class="btn-group dropup">
                        <button
                            type="button"
                            class="btn btn-secondary border-light rounded"
                            data-bs-toggle="dropdown"
                            aria-expanded="false"
                        >
                            <span class="pe-4">Actions</span>
                            <i class="fa-solid fa-bars me-3 fa-lg"></i>
                            <span class="visually-hidden">Toggle Dropdown</span>
                        </button>
						<div class="dropdown-menu" style="width: max-content; max-width: 90vw;">
							<div
								class="d-flex flex-column mw-100 w-100 !px-3 !gap-2"
							>
								{{actions}}
							</div>
						</div>
					</div>
				',
                'dropup_right'   => '
					<div class="btn-group dropup">
                        <button
                            type="button"
                            class="btn btn-secondary border-light rounded"
                            data-bs-toggle="dropdown"
                            aria-expanded="false"
                        >
                            <span class="pe-4">Actions</span>
                            <i class="fa-solid fa-bars me-3 fa-lg"></i>
                            <span class="visually-hidden">Toggle Dropdown</span>
                        </button>
						<div class="dropdown-menu dropdown-menu-end" style="width: max-content; max-width: 90vw;">
							<div
								class="d-flex flex-column mw-100 w-100 !px-3 !gap-2"
							>
								{{actions}}
							</div>
						</div>
					</div>
				',

            ],
        ];

        public function __call(string $method, array $params)
        {
            if (str_starts_with($method, 'add')) {
                $method = str_replace('add', 'append', $method);
            } else {
                $method = 'append' . ucfirst($method);
            }
            return $this->{$method}(...$params);
        }

        public function group($group = 'default'): static
        {
            $this->setConfig('defaultGroup', $group);
            return $this;
        }

        public function get($group = null): array
        {
            $group = $group ?? $this->getConfig('defaultGroup');
            return $this->buttons[$group] ?? [];
        }

        public function append($button, $group = null): static
        {
            $group                   = $group ?? $this->getConfig('defaultGroup');
            $this->buttons[$group][] = $button;
            return $this;
        }

        public function prepend($button, $group = null): static
        {
            $group = $group ?? $this->getConfig('defaultGroup');
            array_unshift($this->buttons[$group], $button);
            return $this;
        }

        public function appendLink(
            $title,
            $url = null,
            $options = [],
            $group = null
        ): static {
            $button = $this->Html->link($title, $url, $options);
            return $this->append($button, $group);
        }

        public function prependLink(
            $title,
            $url = null,
            $options = [],
            $group = null
        ): static {
            $button = $this->Html->link($title, $url, $options);
            return $this->prepend($button, $group);
        }

        public function appendCancel(
            $title = 'Cancel',
            $url = null,
            $options = ['class' => 'btn btn-secondary'],
            $group = null
        ): static {
            $url = $url ?? $this->getView()->getRequest()->getQuery('redirect') ?? $this->getView()->getRequest()->referer() ?? ['action' => 'index'];
            return $this->appendLink($title, $url, $options, $group);
        }

        public function prependCancel(
            $title = 'Cancel',
            $url = null,
            $options = ['class' => 'btn btn-secondary'],
            $group = null
        ): static {
            $url = $url ?? $this->getView()->getRequest()->getQuery('redirect') ?? ['action' => 'index'];
            return $this->prependLink($title, $url, $options, $group);
        }

        public function appendPostLink(
            string            $title,
            array|string|null $url = null,
            array             $options = [],
            string|null       $group = null
        ): static {
            return $this->append($this->Form->postLink($title, $url, $options), $group);
        }

        public function prependPostLink(
            string            $title,
            array|string|null $url = null,
            array             $options = [],
            string|null       $group = null
        ): static {
            return $this->prepend($this->Form->postLink($title, $url, $options), $group);
        }

        protected function _getSubmitButton(
            $text = 'Submit',
            $options = []
        ): string {
            $text = $text ?? 'Submit';

            $form = $options['formName'] ?? $this->Form->getName();
            unset($options['formName']);

            if (!$form) {
                $message =
                    'Unable to create a submit button. The form name is blank, please call Form::create() first.';
                trigger_error($message, E_USER_WARNING);
                return '';
            }

            $onClick = "if (document['$form']?.reportValidity()) { document['$form'].submit(); } else { document['$form']?.classList?.add('was-validated') }";

            if (!empty($options['confirm'])) {
                $onClick                         = $this->_confirm($onClick, '');
                $onClick                         = $this->Form->templater()->format(
                    'confirmJs',
                    [
                        'confirmMessage' => h($options['confirm']),
                        'formName'       => $form,
                        'confirm'        => $onClick,
                    ]
                );
                $options['data-confirm-message'] = $options['confirm'];
                unset($options['confirm']);
            }

            $options['onclick'] = $onClick;
            $options['class']   = $options['class'] ?? 'btn btn-success';

            return $this->Html->tag('button', $text, $options);
        }

        public function appendSubmit(
            $text = '<i class="fa fa-save fa-fw me-3"></i> Save',
            $options = ['class' => 'btn btn-success'],
            $group = null
        ): static {
            $button = $this->_getSubmitButton($text, $options);
            return $this->append($button, $group);
        }

        public function prependSubmit(
            $text = '<i class="fa fa-save fa-fw me-3"></i> Save',
            $options = ['class' => 'btn btn-success'],
            $group = null
        ): static {
            $button = $this->_getSubmitButton($text, $options);
            return $this->prepend($button, $group);
        }

        protected function _getDeleteButton(string|EntityInterface $title, $url = null, $options = []): string
        {

            if ($title instanceof EntityInterface) {
                $entity = $title;

                [, $controller] = pluginSplit($entity->getSource());
                $item = Inflector::humanize(Inflector::underscore(Inflector::singularize($controller)));

                $title = '<i class="fa fa-trash fa-fw me-3"></i> Delete ' . $item;
                $url   = $url ?? [
                    'controller' => $controller,
                    'action'     => 'delete',
                    $entity->id,
                ];

                $options += [
                    'confirm' => "Are you sure you want to delete this {$item}?",
                ];
            }

            if ($url instanceof EntityInterface) {
                $entity = $url;

                [, $controller] = pluginSplit($entity->getSource());
                $item = Inflector::humanize(Inflector::underscore(Inflector::singularize($controller)));

                $url = [
                    'controller' => $controller,
                    'action'     => 'delete',
                    $entity->id,
                ];

                $options += [
                    'confirm' => "Are you sure you want to delete this {$item}?",
                ];
            }

            $options += [
                'confirm' => 'Are you sure you want to delete this item?',
                'class'   => 'btn btn-danger',
            ];

            return $this->Form->postLink($title, $url, $options);
        }

        public function appendDelete(
            string|EntityInterface            $title = '<i class="fa fa-trash fa-fw me-3"></i> Delete',
            array|string|EntityInterface|null $url = null,
            array                             $options = [],
                                              $group = null,
        ): static {
            $button = $this->_getDeleteButton($title, $url, $options);
            return $this->append($button, $group);
        }

        public function prependDelete(
            string            $title = '<i class="fa fa-trash fa-fw me-3"></i> Delete',
            array|string|null $url = null,
            array             $options = [],
                              $group = null,
        ): static {
            $button = $this->_getDeleteButton($title, $url, $options);
            return $this->prepend($button, $group);
        }

        protected function removeFormTags(string $content): string
        {
            $content = preg_replace('/<form\b[^>]*>(.*?)<\/form>/is', '', $content);
            return str_ireplace('</form>', '', $content);
        }

        protected function _getDefaultTemplate(string $group, int $actions): string
        {
            $templates = Hash::expand($this->getConfig('templates'));
            if (isset($templates[$group])) {
                if (!is_array($templates[$group])) {
                    return $group;
                }
                $count = c(array_keys($templates[$group]))->reduce(fn($count, $c) => $c <= $actions ? $c : $count, null);
                if ($count) {
                    return "$group.$count";
                }
            }
            return 'default';
        }

        public function render($group = null, $template = null): string
        {
            $actions = $this->get($group);
            $count   = count($actions);

            if ($template === null) {
                $template = $this->_getDefaultTemplate($group, $count);
            }

            $convertBtnToItem = function ($actions) {
                return array_map(
                    fn($action) => str_replace('btn', 'dropdown-item', $action),
                    $actions
                );
            };

            $dropdownActions = ['actions' => $convertBtnToItem($actions)];
            $actions         = implode(' ', $actions);

            return $this->formatTemplate(
                $template,
                [
                    'actions'        => $actions,
                    'dropdown_left'  => $this->formatTemplate('dropdown_left', $dropdownActions),
                    'dropdown_right' => $this->formatTemplate('dropdown_right', $dropdownActions),
                    'dropup_left'    => $this->formatTemplate('dropup_left', $dropdownActions),
                    'dropup_right'   => $this->formatTemplate('dropup_right', $dropdownActions),
                ]
            );

        }

        public function appendSeparator($group = null)
        {

            $group = $group ?? $this->getConfig('defaultGroup');
            $this->append('<li><hr class="dropdown-divider"></li>', $group);

            return $this;
        }

        public function prependSeparator($group = null)
        {

            $group = $group ?? $this->getConfig('defaultGroup');
            $this->prepend('<li><hr class="dropdown-divider"></li>', $group);

            return $this;
        }


    }
