<?php

namespace Mnv\Core\Interfaces;

use Mnv\Core\Utilities\Cookie\Session;
use Mnv\Http\Request;
use Mnv\Models\Users\UserSettingOption;

/**
 * Class AdminList
 * @package Mnv\Core\Interfaces
 */
class AdminList
{
    public const MODE_PAGE = 'normal';
    public const MODE_LIST = 'list';
    public const MODE_ACTION = 'frame';
    public const MODE_EXPORT = 'excel';
    public const MODE_CONFIG = 'settings';

    protected const MODE_FIELD_NAME = 'mode';

    public $table_id;

    /** @var AdminSorting */
    public $sort;

    public $aHeaders = array();
    public $aVisibleHeaders = array();

    /** @var AdminListRow[] */
    public $aRows = array();
    public $aHeader = array();
    public $arVisibleColumns = array();
    public $aFooter = array();

    public $bEditMode = false;
    public $arEditedRows;

    public $arActions = array();
    public $bShowActions;
    public $bCanBeEdited = false;
    public $arActionsParams = array();
    public $isPublicMode;

    /** @var AdminContextMenuList */
    protected $context = false;
    protected $sContent = false, $sPrologContent = '', $sEpilogContent = '';

    /** @var string */
    protected $mode = null;

    /** @var  Request */
    protected $request;

    protected $managerId;

    protected $pages;
    protected $page;
    protected $url;

    /** @var PageNavigation */
    protected $nav;

    /**
     * AdminList constructor.
     * @param string $url
     * @param string $table_id
     * @param AdminSorting|bool $sort
     * @param $managerId
     */
    public function __construct(string $url, string $table_id, $sort = false, $managerId)
    {
        $this->request  = Request::capture();
        $this->table_id = preg_replace('/[^a-z0-9_]/i', '', $table_id);
        $this->managerId = $managerId;
        $this->sort = $sort;
        $this->url = $url;

        $this->setPublicModeState( 1);

        $this->initMode();
    }

    public function setPublicModeState(bool $mode): void
    {
        $this->isPublicMode = $mode;
        foreach (array_keys($this->aRows) as $index) {
            $this->aRows[$index]->setPublicModeState($mode);
        }
    }

    /**
     * @return void
     */
    protected function initMode(): void
    {
        $this->mode = self::MODE_PAGE;
        $mode = $this->request->get(self::MODE_FIELD_NAME);
        if (is_string($mode) && (in_array($mode, [self::MODE_LIST, self::MODE_ACTION, self::MODE_EXPORT, self::MODE_CONFIG]))){
            $this->mode = $mode;
        }
    }

    protected function initContextMenu(array $menu = [], array $additional = []): void
    {
        if (!empty($menu) || !empty($additional)) {
            $this->context = new AdminContextMenuList($menu, $additional);
        }
    }

    //id, name, content, sort, default
    public function addHeaders($aParams)
    {
        $showAll = $this->request->get('showallcol');
        if ($showAll !== null && $showAll !== '') {
            Session::set('SHALL', $showAll === 'Y');
        }

        $showAll = Session::get('SHALL');

        /** получение из базы выбранных колонок */
        $aCols = array();
        $userColumns = array();
        $gridOptions = new UserSettingOption($this->table_id, $this->managerId);
        $gridColumns = $gridOptions->getVisibleColumns();

        if (!empty($gridColumns)) {
            foreach ($gridColumns as $col) {
                $col = trim($col);
                if ($col <> "") {
                    $aCols[] = $col;
                    $userColumns[$col] = true;
                }
            }
        }

        $bEmptyCols = empty($aCols);
        $userVisibleColumns = array();

        foreach ($aParams as $param) {
            $param["__sort"] = -1;
            $this->aHeaders[$param["id"]] = $param;
            if ($showAll || ($bEmptyCols && $param["default"] == true) || isset($userColumns[$param["id"]])) {
                $this->arVisibleColumns[] = $param["id"];
                $userVisibleColumns[$param["id"]] = true;
            }
        }


        unset($userColumns);

        $aAllCols = ($this->isConfigMode() ? $this->aHeaders : null);

        if (!$bEmptyCols) {
            foreach ($aCols as $i => $col) {
                if (isset($this->aHeaders[$col])) {
                    $this->aHeaders[$col]["__sort"] = $i;
                }
            }
        }

        foreach($this->aHeaders as $id => $arHeader) {
            if (isset($userVisibleColumns[$id])) {
                $this->aVisibleHeaders[$id] = $arHeader;
            }
        }
        unset($userVisibleColumns);

        if ($this->isConfigMode()) {
            $this->showSettings($aAllCols, $aCols, $gridColumns);
        }
    }

    /** @noinspection PhpUnusedParameterInspection  */
    public function showSettings($aAllCols, $aCols, $aOptions)
    {

        die();
    }

    public function AddVisibleHeaderColumn($id)
    {
        if (isset($this->aHeaders[$id]) && !isset($this->aVisibleHeaders[$id])){
            $this->arVisibleColumns[] = $id;
            $this->aVisibleHeaders[$id] = $this->aHeaders[$id];
        }
    }

    public function GetVisibleHeaderColumns()
    {
        return $this->arVisibleColumns;
    }

    /**
     * добавление кнопки настроек
     * @param array $aContext
     * @param bool $showExcelButton
     * @param bool $showSettingsButton
     */
    public function addAdminContextMenu($aContext = [], $showExcelButton = true, $showCsvButton = true, $showSettingsButton = true)
    {
        $config = [];
        if ($showExcelButton) {
            $config['excel'] = true;
        }
        if ($showCsvButton) {
            $config['csv'] = true;
        }
        if ($showSettingsButton) {
            $config['settings'] = true;
        }
        $this->setContextMenu($aContext, [], $config);
    }

    /**
     * @param array $menu
     * @param array $additional
     * @param array $config
     */
    public function setContextMenu(array $menu = [], array $additional = [], array $config = []): void
    {
        $this->initContextMenu($menu, array_merge($additional, $this->getSystemContextMenu($config)));
    }

    /**
     * кнопки настройки таблицы и экспорт excel
     * @param array $config
     * @return array
     */
    protected function getSystemContextMenu(array $config = []): array
    {
        $result = [];
        if (isset($config['excel'])) {
            $result[] = [
                "TEXT"      => "xlsx",
                "TITLE"     => "Export to XLSX",
                "LINK"      => $this->table_id . "?action=export&type_file=xlsx",
                "ICON"      => '<i class="ph-file-xls me-2"></i>',
            ];
        }
        if (isset($config['csv'])) {
            $result[] = [
                "TEXT"      => "csv",
                "TITLE"     => "Export to CSV",
                "LINK"      => $this->table_id . "?action=export&type_file=csv",
                "ICON"      => '<i class="ph-file-xls me-2"></i>',
            ];
        }
        if (isset($config['settings'])) {
            $result[] = [
                "TEXT"      => "Настройки",
                "TITLE"     => "Настройки",
                "CLICK"     => "setting_table",
                "ICON"      => '<i class="ph-gear me-2"></i>',
            ];
        }

        return $result;
    }


    /**
     * Добавление строки
     * @param false $id
     * @param array $arRes
     * @param false $link
     * @param false $title
     * @return mixed|AdminListRow
     */
    public function &addRow($id = false, $arRes = [], $link = false, $title = false)
    {
//        print_r($arRes);
        $row = new AdminListRow($this->aHeaders, $this->table_id);
        $row->id    = $id;
        $row->arRes = $arRes;
        $row->link  = $link;
        $row->title = $title;
        $row->pList = &$this;

        if ($id) {
            if($this->bEditMode && in_array($id, $this->arEditedRows)) {
                $row->bEditMode = true;
            } elseif(!empty($this->arUpdateErrorIDs) && in_array($id, $this->arUpdateErrorIDs)) {
                $row->bEditMode = true;
            }
        }

        $row->setPublicModeState($this->getPublicModeState());

        $this->aRows[] = &$row;
        return $row;
    }

    public function addFooter($aFooter)
    {
        $this->aFooter = $aFooter;
    }

    /**
     * @param $pages
     * @param int $page
     * @param $buildQueryString
     * @return string
     */
    public function displayTable($arParams = array(), $pages, int $page, $buildQueryString)
    {

        $html = '<div class="card border shadow-sm" id="' . $this->table_id . '_result_div">';

        /** table */
        $html .= $this->display();
        /** end table */

        /** pagination */
        $this->nav = new PageNavigation($pages);
        $pagination = $this->nav->setUrl($this->url)->setCurrentPage($page)->setQueryString($buildQueryString)->pagination();

//        print_r($nav);

        $html .= $pagination;
        /** end pagination */


        $html .= '</div>';

        return $html;
    }

    public function display(): string
    {

        $table = '<div class="table-responsive">';

//        if ($this->sContent === false) {
//            $table .= $this->context ? '' : ' adm-list-table-without-header';
//        }

        /** кнопки над таблицей */
        if ($this->context) {
            $table .= $this->context->show();
        }

        if ($this->bEditMode && !$this->bCanBeEdited) {
            $this->bEditMode = false;
        }

        if ($this->sContent !== false) {
            return $this->sContent;
        }

        $bShowSelectAll = (count($this->arActions) > 0 || $this->bCanBeEdited);
        $this->bShowActions = false;

        foreach ($this->aRows as $row) {
            if (!empty($row->aActions)) {
                $this->bShowActions = true;
                break;
            }
        }

        $colSpan = 0;
        /** TABLE */
        $table .= '<table class="table table-xs table-togglable table-striped table-hover" id="' . $this->table_id .'">';

            /** THEAD */
            $table .= '<thead>';

                /** TR */
                $table .= '<tr>';

                /** TH */

                if ($bShowSelectAll) {
                    $table .= '<th class="text-center" width="30"><div class="form-check"><input type="checkbox" class="form-check-input content_check_all"></div></th>';
                    $colSpan++;
                }

                foreach($this->aVisibleHeaders as $header) {
                    $attrs = '';

                    if (isset($header["class"])) {
                        $attrs .= 'class="' . $header["class"] . '"';
                    }

                    if (isset($header["width"])) {
                        $attrs .= ' width="' . $header["width"] . '"';
                    }

                    $table .= '<th ' . $attrs . '>' . $header["content"] . '</th>';

                    $colSpan++;
                }

                if ($this->bShowActions) {
                    $table .= '<th class="text-center text-muted" width="30" title="Колонка действий"><i class="ph-check"></i></th>';
                    $colSpan++;
                }
                /** END TH */

                $table .= '</tr>';
            /** END TR */

            $table .= '</thead>';
            /** END THEAD */

            /** TBODY */
            $table .= '<tbody>';

            /** Таблица данных  */
            if (!empty($this->aRows)) {
                foreach ($this->aRows as $row) {
                    $table .= $row->display();
                }
            }
            /** если пустые thead tr th  */
            else if(!empty($this->aHeaders)) {
                $table .= '<tr><td colspan="' . $colSpan . '" class="text-center"> -- Данные пусты -- </td></tr>';
            }
            /** если таблица пуста  */
            else {
                $table .= '<tr><td colspan="' . $colSpan . '" class="text-center"> -- Данные пусты -- </td></tr>';
            }


            $table .= '</tbody>';
            /** END TBODY */
        $table .= '</tbody>';

        $table .= '</table>';
        /** END TABLE */

//        $this->showActionTable();

        $table .= '</div>';

        return $table;
    }


    public function showActionTable()
    {
        if (empty($this->arActions) && !$this->bCanBeEdited) {
            return;
        }

        $act = '<div class="adm-list-table-footer" id="' . $this->table_id . '_footer' . $this->bEditMode || !empty($this->arUpdateErrorIDs) ? '_edit' : '' .'">';
        $act .= '<input type="hidden" name="action_button" id="'. $this->table_id . '_action_button" value="" />';

        if($this->bEditMode || !empty($this->arUpdateErrorIDs)) {
            $act = '<input type="hidden" name="save" id="' . $this->table_id . '_hidden_save" value="Y">';
            $act .= '<input type="submit" class="adm-btn-save" name="save" value="admin_lib_list_edit_save" title="admin_lib_list_edit_save_title" />';
            $act .= '<input type="button" name="cancel" value="edit_cancel" title="edit_cancel_title" />';

        } else { //($this->bEditMode || count($this->arUpdateErrorIDs)>0)
            if($this->arActionsParams["disable_action_target"] <> true) {
                $act .=  '<span class="adm-selectall-wrap">
                        <input type="checkbox" class="adm-checkbox adm-designed-checkbox" name="action_target" value="selected" id="action_target" onclick="if(this.checked && !confirm(' . CUtil::JSEscape("admin_lib_list_edit_for_all_warn") . ')) {this.checked=false;} ' .$this->table_id .'.EnableActions();" title="admin_lib_list_edit_for_all" />
                        <label for="action_target" class="adm-checkbox adm-designed-checkbox-label"></label>
                        <label title="admin_lib_list_edit_for_all" for="action_target" class="adm-checkbox-label">admin_lib_list_for_all</label>
                    </span>';
            }

            $this->bCanBeDeleted = array_key_exists("delete", $this->arActions);

            if ($this->bCanBeEdited || $this->bCanBeDeleted){
                    $act .=  '<span class="adm-table-item-edit-wrap'.(!$this->bCanBeEdited || !$this->bCanBeDeleted ? ' adm-table-item-edit-single' : '').'">';
                    if($this->bCanBeEdited){
                        echo '<a href="javascript:void(0)" class="adm-table-btn-edit adm-edit-disable" id="action_edit_button"></a>';
                    }
                    if ($this->bCanBeDeleted) {
                        $act .=  '<a href="javascript:void(0);" class="adm-table-btn-delete adm-edit-disable" title="admin_lib_list_del_title" class="context-button icon action-delete-button-dis" id="action_delete_button"></a>';
                    }
                    $act .=  '</span>';
                }

            $onchange = '';
            if (isset($this->arActionsParams["select_onchange"])){
                    if (is_array($this->arActionsParams["select_onchange"])){
                        $onchange = implode(' ', $this->arActionsParams["select_onchange"]);
                    }elseif (is_string($this->arActionsParams["select_onchange"])){
                        $onchange = $this->arActionsParams["select_onchange"];
                    }
                }

            $list = '';
            $html = '';
            $buttons = '';
            $actionList = array_filter($this->arActions);
            if (isset($actionList['delete'])){
                    unset($actionList['delete']);
                }

            $allowedTypes = [
                    'button' => true,
                    'html' => true
                ];

            foreach($actionList as $k=>$v) {
                    if(is_array($v)){
                        if (isset($v['type']) && isset($allowedTypes[$v['type']])){
                            switch ($v["type"]){
                                case 'button':
                                    $buttons .= '<input type="button" name="" value="'.htmlspecialcharsbx($v['name']).'" onclick="'.(!empty($v["action"])? htmlspecialcharsbx($v['action']) : 'document.forms[\'form_'.$this->table_id.'\'].elements[\'action_button\'].value=\''.htmlspecialcharsbx($v["value"]).'\'; '.htmlspecialcharsbx($this->ActionPost()).'').'" title="'.htmlspecialcharsbx($v["title"]).'" />';
                                    break;
                                case 'html':
                                    $html .= '<span class="adm-list-footer-ext">'.$v["value"].'</span>';
                                    break;
                            }
                        }else{
                            $list .= '<option value="'.htmlspecialcharsbx($v['value']).'"'.($v['action']?' custom_action="'.htmlspecialcharsbx($v['action']).'"':'').'>'.htmlspecialcharsex($v['name']).'</option>';
                        }
                    }else{
                        $list .= '<option value="'.htmlspecialcharsbx($k).'">'.htmlspecialcharsex($v).'</option>';
                    }
                }
            unset($actionList, $k, $v);
            unset($allowedTypes);

            if ($buttons != '') {
                    $act .=  '<span class="adm-list-footer-ext">' . $buttons . '</span>';
                }
            if ($list != '') {

                    $act .= ' <span class="adm-select-wrap">';
                    $act .= '<select name="action" id="' . $this->table_id . '_action" class="adm-select"' . ($onchange != '' ? ' onchange="' . htmlspecialcharsbx($onchange) . '"' : '') . '>';
                    $act .= '<option value="">admin_lib_list_actions</option>';
                    $list;
                    $act .= '</select>';
                    $act .= '</span>';

                    if ($html != '') {
                        $html;

                        $act .= '<input type="submit" name="apply" value="admin_lib_list_apply" onclick="if(this.form.action[this.form.action.selectedIndex].getAttribute(custom_action)){eval(this.form.action[this.form.action.selectedIndex].getAttribute(custom_action));return false;}" disabled="disabled" class="adm-table-action-button" />';
                    }

                    $act .= '<span class="adm-table-counter" id="' . $this->table_id . '_selected_count">admin_lib_checked: <span>0</span></span>';

                }

            $act .= '</div>';

            return $act;
        }
    }


    /**
     * @return array|false
     */
    public function GroupAction()
    {
        $this->PrepareAction();

        $action = $this->GetAction();
        if ($action === null){
            return false;
        }

        if ($action == "edit") {
            $arID = $this->GetGroupIds();
            if ($arID !== null){
                $this->arEditedRows = $arID;
                $this->bEditMode = true;
            }
            return false;
        }

        if (!$this->IsGroupActionToAll()){
            $arID = $this->GetGroupIds();
            if ($arID === null){
                $arID = false;
            }
        } else {
            $arID = array('');
        }

        return $arID;
    }

    protected function PrepareAction()
    {
        if (!empty($_REQUEST['action_button'])) {
            $_REQUEST['action'] = $_REQUEST['action_button'];
        }
    }

    /**
     * @return string|null
     */
    public function GetAction()
    {
        return ($_REQUEST['action'] ?? null);
    }

    /**
     * @return array|null
     */
    protected function GetGroupIds()
    {
        $result = null;
        if (isset($_REQUEST['ID']))
        {
            $result = (!is_array($_REQUEST['ID']) ? array($_REQUEST['ID']) : $_REQUEST['ID']);
        }
        return $result;
    }

    /**
     * Returns true if the user has set the flag "To all" in the list.
     *
     * @return bool
     */
    public function IsGroupActionToAll()
    {
        return (isset($_REQUEST['action_target']) && $_REQUEST['action_target'] === 'selected');
    }



    /**
     * @return string
     */
    public function getCurrentMode(): string
    {
        return $this->mode;
    }


    public function getPublicModeState(): bool
    {
        return $this->isPublicMode;
    }

    /**
     * @return bool
     */
    public function isConfigMode(): bool
    {
        return $this->getCurrentMode() === self::MODE_CONFIG;
    }

    /**
     * @return bool
     */
    public function isActionMode(): bool
    {
        return $this->getCurrentMode() === self::MODE_ACTION;
    }

    /**
     * @return bool
     */
    public function isListMode(): bool
    {
        return $this->getCurrentMode() === self::MODE_LIST;
    }

    public function ActionRedirect($url)
    {
        $url = (string)$url;
        if ($this->isPublicMode)
        {
            $selfFolderUrl = (defined("SELF_FOLDER_URL") ? SELF_FOLDER_URL : "/bitrix/admin/");
            if (mb_strpos($url,$selfFolderUrl) === false)
            {
                $url = $selfFolderUrl.$url;
            }
        }

        return "BX.adminPanel.Redirect([], '".static::getUrlWithLanguage($url)."', event);";
    }

    public function ActionAjaxReload($url)
    {
        return $this->table_id.".GetAdminList('".static::getUrlWithLanguage((string)$url)."');";
    }
}