<?php

namespace apexl\Io\modules\display\components;

use apexl\Io\includes\Entity;
use apexl\Io\includes\Routes;
use apexl\Io\modules\component\entities\componentEntity;
use Closure;

class EntityDisplayTable extends componentEntity
{
    protected $dataSrc;
    protected $filters;
    protected Entity $entity;
    protected $hideDisabled = false;

    public function __construct(Entity $entity = null, $replacements = [])
    {
        parent::__construct();
        $this->setName("DataTable");
        if ($entity !== null) {
            $this->setEntity($entity, $replacements);

            $hideCols = array_filter(
                $entity->getFieldConfig(),
                fn ($config) => $config['table'] ?? null === 'hide'
            );

            if ($hideCols) {
                $this->hideCols(array_keys($hideCols));
            }
        }
        $this->displayPagination();
    }

    public function setEntity(Entity $entity, $replacements = [])
    {
        $this->entity = $entity;
        $this->dataSrc = Routes::getRoutePattern($entity->getEntityName().'.get', $replacements);
        $this->src($this->dataSrc);
        return $this;
    }

    public function setFilters($filters)
    {
        $this->filters = $filters;
        $this->src($this->dataSrc);
        return $this;
    }

    public function showCols(array $cols): EntityDisplayTable
    {
        $this->addProperty('showCols', $cols);
        return $this;
    }

    public function hideCols(array $cols): EntityDisplayTable
    {
        $this->addProperty('hideCols', $cols);
        return $this;
    }

    public function displayPagination($display = true)
    {
        $this->addProperty('showPagination', $display);
        return $this;
    }

    public function displayShortTotals($display = true)
    {
        $this->addProperty('displayShortTotals', $display);
        return $this;
    }

    public function colspans($colspans = [])
    {
        $this->addProperty('colspans', $colspans);
        return $this;
    }

    public function hideIdColumn($display = true)
    {
        $this->addProperty('hideIdColumn', $display);
        return $this;
    }

    public function src($dataSrc)
    {
        $this->dataSrc = $dataSrc;
        $src = $this->dataSrc ?? '';
        if ($this->filters) {
            $src .= '?'.ltrim((string) $this->filters, '?').'&asTable=1';
        } else {
            $src .= '?asTable=1';
        }
        $this->addProperty('dataSrc', $src);
        return $this;
    }

    public function addCommonButtons(): EntityDisplayTable
    {
        $buttons = [
            'get' => Closure::fromCallable(function ($routeName) : self {
                return $this->addViewButton($routeName);
            }),
            'put' => Closure::fromCallable(function ($routeName) : self {
                return $this->addEditButton($routeName);
            }),
            'delete' => Closure::fromCallable(function ($routeName) : self {
                return $this->addDeleteButton($routeName);
            }),
        ];

        $entityName = $this->entity->getEntityName();

        foreach ($buttons as $routeAppend => $callable) {
            $routeName = sprintf('%s.display.%s', $entityName, $routeAppend);
            if (Routes::getRoutePattern($routeName)) {
                $callable($routeName);
            }
        }

        return $this;
    }

    /**
     * @param $routeName
     */
    public function addViewButton($routeName): EntityDisplayTable
    {
        $this->addButton($routeName, 'eye', $this->getAccessFromRoute($routeName));
        return $this;
    }

    /**
     * @param $routeName
     */
    public function addEditButton($routeName): EntityDisplayTable
    {
        $this->addButton($routeName, 'edit', $this->getAccessFromRoute($routeName));
        return $this;
    }

    /**
     * @param $routeName
     */
    public function addDeleteButton($routeName): EntityDisplayTable
    {
        $this->addButton($routeName, 'trash', $this->getAccessFromRoute($routeName));
        return $this;
    }

    /**
     * @param $routeName
     */
    public function addPostButton($routeName, array $replacements = [], string $icon ='', bool $disabled = null): EntityDisplayTable
    {
        if (is_null($disabled)) {
            $disabled = $this->getAccessFromRoute($routeName);
        }
        $button = (new TableButton())
            ->addRoute(Routes::getRoutePattern($routeName, $replacements, false))
            ->addIcon($icon)
            ->isPost()
            ->addClass($this->entity->getEntityTrueName().'_table__btn')
            ->addClass($this->entity->getEntityTrueName().'_table__btn-'.$icon)
            ->addClass('table__btn')
            ->addClass('table__btn-'.$icon);
        if ($disabled) {
            $button->addRoute('#');
            $button->addClass($this->entity->getEntityTrueName() . '_table__btn-disabled');
            $button->addClass('table__btn-disabled');
            $button->disabled($disabled);
            if ($this->hideDisabled) {
                //do not add the button to the component
                return $this;
            }
        }
        $this->addComponent($button);
        return $this;
    }

    /**
     * @param $routeName
     */
    public function addButton($routeName, string $icon ='', bool $disabled = false, bool $openInNewWindow = false): EntityDisplayTable
    {
        $entityTrueName = isset($this->entity) && $this->entity ? $this->entity->getEntityTrueName() : '';

        $button = (new TableButton())
            ->addRoute(Routes::getRoutePattern($routeName, [], false))
            ->addIcon($icon)
            ->addClass($entityTrueName.'_table__btn')
            ->addClass($entityTrueName.'_table__btn-'.$icon)
            ->addClass('table__btn')
            ->addClass('table__btn-'.$icon);
        if ($openInNewWindow) {
            $button->openInNewWindow();
        }
        if ($disabled) {
            $button->addRoute('#');
            $button->addClass($entityTrueName . '_table__btn-disabled');
            $button->addClass('table__btn-disabled');
            $button->disabled($disabled);
            if ($this->hideDisabled) {
                //do not add the button to the component
                return $this;
            }
        }
        $this->addComponent($button);
        return $this;
    }

    public function hideDisabled(bool $value = true): EntityDisplayTable
    {
        $this->hideDisabled = $value;
        return $this;
    }

    /**
     * @param $routeName
     */
    protected function getAccessFromRoute($routeName): bool
    {
        $route = Routes::getRoute($routeName);
        if (($route ?? false) && $permission = $route->getArgs('permission')) {
            //we need to pass the opposite here as disabled is false if access it true.
            return !$this->currentUser->isAllowed($permission);
        }
        //no permission? just return true.
        return (bool) $route; //no route? return false.
    }
}
