<?php

namespace GriffinForms\Admin\Html\Pages\Lists;

use GriffinForms\Admin\Html\Pages\Lists\ListTable;
use GriffinForms\Admin\Html\Pages\Lists\ListPagination;

class Format extends \GriffinForms\Admin\Html\Pages\Format
{
    use ListTable;
    use ListPagination;
    
    protected $config;
    protected $meta;
    protected $type;
    protected $sql;
    protected $lang;
    protected $secure;
    protected $css;
    protected $list_url;
    protected $filter_links;
    protected $filter_names;
    protected $bulk_actions;
    protected $column_registry;
    protected $column_prefs;
    protected $list_columns;
    protected $sortables;
    protected $list_props;
    protected $list_size = 10;
    protected $order_by = 'created';
    protected $order = 'desc';
    protected $paged = '1';
    protected $search = '';
    protected $date_from = '';
    protected $date_to = '';
    protected $result_count;
    protected $total_pages;
    protected $list_data;
    protected $row_actions;
    protected $js_data;
    protected $js_object;
    protected $js;
    
    protected function setColumnRegistry()
    {
        $this->column_registry = \GriffinForms\Admin\Html\Pages\Lists\ColumnRegistry::getInstance();
    }

    protected function setColumnPrefs()
    {
        $this->column_prefs = \GriffinForms\Admin\Html\Pages\Lists\ColumnPreferences::getInstance();
    }

    protected function registerColumns(): void
    {
        // Subclasses override this to register their columns with $this->column_registry.
        // Base implementation only fires the third-party hook.
        do_action(
            'griffinforms_register_columns_' . sanitize_key((string) $this->type),
            $this->column_registry,
            $this->type
        );
    }

    protected function pageModals()
    {
        $this->deleteItemsModal();
        $this->deleteListItemModal();
        (new \GriffinForms\Admin\Html\Modals\ColumnManager())->html();
    }

    protected function columnManagerButton(): void
    {
        $label    = esc_attr__('Manage columns', 'griffinforms-form-builder');
        $icon_url = esc_url($this->config->getRootUrl() . 'admin/images/button-icons/columns.svg');
        $icon_style = 'display:inline-block;width:22px;height:22px;vertical-align:middle;'
            . 'background-color:var(--wp-admin-theme-color,#2271b1);'
            . '-webkit-mask:url(' . $icon_url . ') center/contain no-repeat;'
            . 'mask:url(' . $icon_url . ') center/contain no-repeat;';
        echo '<button type="button" class="button gf-column-manager-btn ms-2"';
        echo ' data-bs-toggle="modal" data-bs-target="#gf-column-manager-modal"';
        echo ' title="' . $label . '">';
        echo '<span style="' . esc_attr($icon_style) . '" aria-hidden="true"></span>';
        echo ' <span class="screen-reader-text">' . esc_html__('Manage columns', 'griffinforms-form-builder') . '</span>';
        echo '</button>';
    }

    protected function columnWidthStyles(): void
    {
        $prefs = $this->column_prefs->load($this->type);
        if (empty($prefs['widths'])) {
            return;
        }
        echo '<style>';
        foreach ($prefs['widths'] as $col => $width) {
            $col   = sanitize_key($col);
            $width = preg_replace('/[^0-9a-z.%]/', '', strtolower((string) $width));
            if ($col === '' || $width === '') {
                continue;
            }
            echo '.column-' . esc_attr($col) . ' { width: ' . esc_attr($width) . ' !important; }';
        }
        echo '</style>';
    }
    
    protected function setJsData()
    {
        $js_bulk_actions = [];
        foreach ((array) $this->bulk_actions as $key => $value) {
            if (is_int($key)) {
                $js_bulk_actions[(string) $value] = $this->lang->getText((string) $value, 'bulk_action');
            } elseif (is_array($value)) {
                $js_bulk_actions[(string) $key] = (string) ($value['label'] ?? $this->lang->getText((string) $key, 'bulk_action'));
            } else {
                $js_bulk_actions[(string) $key] = (string) $value;
            }
        }

        $this->js_data = [
            'item_type'    => $this->getNormalizedListKey($this->type),
            'items_type'   => $this->getNormalizedListKey($this->meta),
            'bulk_actions' => $js_bulk_actions,
        ];
    }
    
    protected function setCss()
    {
        $css_file = $this->config->getRootUrl() . 'admin/css/griffinforms-lists.css';
        wp_enqueue_style('griffinforms-lists-css', $css_file, [], '1.0', false);
    }
    
    protected function setJs()
    {
        $js_file = $this->config->getRootUrl() . 'admin/js/griffinforms-lists.js';
        wp_enqueue_script('griffinforms-lists-js', $js_file, ['jquery'], '1.0', false);

        // Column manager data is built here (not in setJsData) because $js_data is
        // declared in the grandparent Pages\Format and fires in setAll() before the
        // Lists\Format-specific properties (column_registry, list_columns) are set.
        // $js (this property) is new to Lists\Format, so it fires after all of them.
        if ($this->column_registry && $this->column_registry->hasColumns($this->type)) {
            $registry    = $this->column_registry;
            $prefs       = $this->column_prefs->load($this->type) ?? [];
            $all_columns = $registry->getColumns($this->type);
            $locked      = $registry->getLockedColumns($this->type);
            $active_keys = $this->list_columns;

            $columns_for_js = [];
            foreach ($all_columns as $key => $config) {
                if (in_array($key, $locked, true)) {
                    continue;
                }
                $columns_for_js[] = [
                    'key'             => $key,
                    'label'           => $config['label'],
                    'active'          => in_array($key, $active_keys, true),
                    'variants'        => $config['variants'],
                    'default_variant' => $config['default_variant'],
                    'saved_variant'   => $prefs['variants'][$key] ?? $config['default_variant'],
                    'saved_width'     => $prefs['widths'][$key] ?? $config['default_width'],
                ];
            }

            $active_order  = array_values(array_filter($active_keys, fn($k) => !in_array($k, $locked, true)));
            $active_cols   = array_filter($columns_for_js, fn($c) => $c['active']);
            $inactive_cols = array_filter($columns_for_js, fn($c) => !$c['active']);
            usort($active_cols, fn($a, $b) =>
                array_search($a['key'], $active_order) - array_search($b['key'], $active_order)
            );

            $this->js_data['column_manager'] = [
                'list_type'          => $this->type,
                'columns'            => array_values(array_merge($active_cols, $inactive_cols)),
                'list_size'          => $this->list_size,
                'list_size_options'  => [10, 25, 50, 100],
                'crowding_threshold' => 8,
                'nonce'              => wp_create_nonce('gf_list_prefs'),
                'save_action'        => 'gf_save_list_prefs',
                'reset_action'       => 'gf_reset_list_prefs',
                'ajax_url'           => admin_url('admin-ajax.php'),
                'drag_handle_url'    => $this->config->getRootUrl() . 'admin/images/button-icons/drag-handle.svg',
            ];
        }

        $this->js_data['i18n'] = [
            'confirmReset' => __('Reset columns to defaults for this list?', 'griffinforms-form-builder'),
        ];

        if (!empty($this->js_data)) {
            wp_localize_script('griffinforms-lists-js', 'griffinformsListsData', $this->js_data);
        }
    }
    
    protected function setListUrl()
    {
        $this->list_url = get_admin_url() . 'admin.php?page=griffinforms-' . $this->getNormalizedListKey($this->meta);
    }

    protected function getNormalizedListKey($value): string
    {
        return is_string($value) ? strtolower($value) : '';
    }
    
    protected function setFilterLinks()
    {
        $this->filter_links = array('all');
    }
    
    protected function setFilterNames()
    {
        $this->filter_names = array(
            'search',
            'date_from',
            'date_to',
        );
    }
    
    protected function setBulkActions()
    {
        $this->bulk_actions = array(
            'deleteItems'
        );
    }
    
    protected function setListColumns()
    {
        $this->registerColumns(); // populate registry and fire third-party hook

        $prefs = $this->column_prefs->load((string) $this->type);

        if ($prefs !== null && !empty($prefs['columns'])) {
            $locked = $this->column_registry->getLockedColumns((string) $this->type);
            $saved  = array_values(array_diff((array) $prefs['columns'], $locked));
            $this->list_columns = array_merge($locked, $saved);
        } else {
            $this->list_columns = $this->column_registry->getDefaultColumns((string) $this->type);
        }
    }

    protected function setListSize(): void
    {
        $prefs = $this->column_prefs->load((string) $this->type);
        if ($prefs !== null && isset($prefs['list_size'])) {
            $allowed = [10, 25, 50, 100];
            $size    = absint($prefs['list_size']);
            $this->list_size = in_array($size, $allowed, true) ? $size : 10;
        }
        // else: property keeps its class-level default of 10.
    }
    
    protected function setSortables()
    {
        if (!$this->column_registry || !$this->column_registry->hasColumns($this->type)) {
            $this->sortables = ['name', 'created'];
            return;
        }
        $this->sortables = [];
        foreach ($this->column_registry->getColumns($this->type) as $key => $col) {
            if (!empty($col['sortable'])) {
                $this->sortables[] = $key;
            }
        }
    }
    
    protected function setListProps()
    {
        $allowed_props = [
            'paged' => 'absint',
            'order' => 'sanitize_text_field',
            'order_by' => 'sanitize_text_field',
            'search' => 'sanitize_text_field',
            'date_from' => 'sanitize_text_field',
            'date_to' => 'sanitize_text_field',
        ];

        foreach ($allowed_props as $prop => $sanitizer) {
            if (isset($_GET[$prop])) {
                $this->$prop = call_user_func($sanitizer, wp_unslash($_GET[$prop]));
            }
        }
    }
    
    protected function getListFilters()
    {
        $filters = array();
        foreach ($this->filter_names as $name) {
            $filters[$name] = isset($_GET[$name]) ? sanitize_text_field(wp_unslash($_GET[$name])) : '';
        }

        return array_filter($filters);

    }
    
    protected function getListArgs()
    {
        return array(
            'item_type' => $this->type,
            'list_size' =>$this->list_size,
            'order_by' =>$this->order_by,
            'order' => $this->order,
            'offset' => (absint($this->paged) - 1) * absint($this->list_size),
            'filters' => $this->getListFilters(),
        );
    }
    
    protected function createUrl($data = null)
    {
        if (empty($data)) {
            $data = $this->getListArgs();    
        }
        
        $filters = $data['filters'];
        unset($data['filters']);
        
        $url_data = array_merge($data, $filters);
        return $this->list_url . '&' . http_build_query($url_data);
    }
    
    protected function setResultCount()
    {
        $data = $this->getListArgs();
        $this->result_count = $this->sql->resultsCount($data);
    }
    
    protected function setTotalPages()
    {
        $this->total_pages = ceil($this->result_count / $this->list_size);
    }
    
    protected function setListData()
    {
        $data = $this->getListArgs();
        $this->list_data = $this->sql->listData($data);
    }
    
    protected function setRowActions()
    {
        $this->row_actions = array(
            'edit',
            'trash'
        );
    }
    
    protected function isFiltered()
    {
        if (empty($this->getListFilters())) {
            return false;
        } else {
            return true;
        }
    }
    
    protected function isSorted()
    {
        $orderby = isset($_GET['orderby']) ? sanitize_text_field(wp_unslash($_GET['orderby'])) : '';
        return !empty($orderby);
    }
    
    protected function isOrder()
    {
        $order = isset($_GET['order']) ? sanitize_text_field(wp_unslash($_GET['order'])) : '';
        return !empty($order);
    }
    
    protected function isSearched()
    {
        $search = isset($_GET['search']) ? sanitize_text_field(wp_unslash($_GET['search'])) : '';
        return !empty($search);
    }
    
    protected function deleteItemsModal()
    {
        $for = 'DeleteItems';
        $data = array('item_type' => $this->type);
        $this->newModal($for, '', $data);
    }

    protected function deleteListItemModal()
    {
        $for = 'DeleteListItem';
        $data = array('item_type' => $this->type);
        $this->newModal($for, '', $data);
    }
    
    protected function addNewButton()
    {
        $url = admin_url('admin.php?page=griffinforms-' . $this->type);
        echo '<a href="' . esc_url($url) . '" class="page-title-action">' . esc_html($this->lang->getText('add_new', $this->type)) . '</a>';
    }
    
    protected function filterLinks()
    {
        echo '<ul class="subsubsub">';
        
        foreach ($this->filter_links as $index => $filter_link) {
            $link = $filter_link . 'FilterLink';
            
            echo ' <li class="' . esc_attr($filter_link) . '">';
            if (method_exists($this, $link)) {
                $this->$link();
            } else {
                echo esc_html($link);
            }
            
            if ($index !== count($this->filter_links) - 1) {
                echo ' |';
            }
            
            echo '</li>';
        }
        
        echo '</ul>';
    }
    
    protected function allFilterLink()
    {
        $count = $this->sql->getItemCount($this->type);
        $link_class = '';
        
        if (empty($this->getListFilters())) {
            $link_class = 'current';
        }
        
        echo '<a href="' . esc_url($this->list_url) . '" class="' . esc_attr($link_class) . '" aria-current="page">';
        esc_html_e('All', 'griffinforms-form-builder');
        echo ' <span class="count">(';
        echo absint($count);
        echo ')</span>';
        echo '</a>';
    }
    
    protected function searchBox()
    {
        echo '<p class="search-box">';
        echo '<input type="search" id="post-search-input" name="search" value="' . esc_attr($this->search) . '"> ';
		echo '<input type="submit" id="search-submit" class="button" value="' . esc_attr($this->lang->getText($this->meta, 'search_btn_label')) . '"></p>';
    }
    
    protected function bulkActions($position = 'top')
    {
        if (empty($this->bulk_actions)) {
            return;
        }

        $select_id = 'gf-bulk-action-select-' . $position;
        $apply_id  = 'gf-bulk-action-apply-' . $position;

        echo '<div class="alignleft actions bulkactions">';

        // Build a normalised map: slug => ['label' => string, 'disabled' => bool]
        $normalised = [];
        foreach ($this->bulk_actions as $key => $value) {
            if (is_int($key)) {
                // flat array — value is the slug; label comes from lang
                $slug  = (string) $value;
                $label = $this->lang->getText($slug, 'bulk_action');
                $normalised[$slug] = ['label' => $label, 'disabled' => false];
            } elseif (is_array($value)) {
                // associative with meta array: ['label' => ..., 'disabled' => ...]
                $slug  = (string) $key;
                $label = (string) ($value['label'] ?? $this->lang->getText($slug, 'bulk_action'));
                $normalised[$slug] = ['label' => $label, 'disabled' => !empty($value['disabled'])];
            } else {
                // associative slug => label string
                $slug  = (string) $key;
                $normalised[$slug] = ['label' => (string) $value, 'disabled' => false];
            }
        }

        // Modal map only for non-disabled actions
        $modal_map = [];
        foreach ($normalised as $slug => $meta) {
            if (!$meta['disabled']) {
                $modal_map[strtolower($slug)] = 'griffinforms-' . strtolower($slug) . '-modal';
            }
        }

        echo '<select name="action" id="' . esc_attr($select_id) . '" class="gf-bulk-action-select" data-gf-modal-map=\'' . esc_attr(wp_json_encode($modal_map)) . '\'>';
        echo '<option value="-1">';
        echo esc_html($this->lang->getText('bulk_action'));
        echo '</option>';

        foreach ($normalised as $slug => $meta) {
            if ($meta['disabled']) {
                echo '<option value="' . esc_attr(strtolower($slug)) . '" class="hide-if-no-js" disabled>';
            } else {
                echo '<option value="' . esc_attr(strtolower($slug)) . '" class="hide-if-no-js">';
            }
            echo esc_html($meta['label']);
            echo '</option>';
        }

        echo '</select>';

        echo '<a id="' . esc_attr($apply_id) . '" class="button action gf-bulk-action-apply disabled" value="Apply" data-bs-toggle="modal"';
        echo ' data-bs-target="">';
        echo esc_html($this->lang->getText('apply', 'list_action'));
        echo '</a>';
		echo '</div>';
    }
    
    protected function resetFiltersBtn()
    {
        if (!$this->isFiltered()) {
            return;
        }
        
        echo '<div class="alignleft actions ms-2">';
        echo '<a class="button" href="' . esc_url($this->list_url) . '">Reset Filters</a>';
		echo '</div>';
    }
    
    protected function itemFilters()
    {
        
    }

    protected function pageAlerts()
    {
    }

    protected function listHeading()
    {
        echo '<h1 class="wp-heading-inline">' . esc_html($this->lang->getText($this->meta, 'list_heading')) . '</h1>';
        $this->addNewButton();
        echo '<hr class="wp-header-end">';
    }
    
    protected function dateFilter()
    {
        echo '<input class="griffinforms-datepicker" type="search" name="date_from" value="' . esc_attr($this->date_from) . '" placeholder="' . esc_attr($this->lang->getText('date_from', 'placeholder')) . '" style="width: 10em;"> ';
        echo '<input class="griffinforms-datepicker" type="search" name="date_to" value="' . esc_attr($this->date_to) . '" placeholder="' . esc_attr($this->lang->getText('date_to', 'placeholder')) . '" style="width: 10em;"> ';
        echo '<input type="submit" id="post-query-submit" class="button">';
    }
    
    public function html()
    {
        $this->setSnackBar();
        $this->pageModals();
        
        echo '<div class="wrap">';

        $this->pageAlerts();
        $this->listHeading();
        $this->filterLinks();
        
        echo '<form method="get">';
        echo '<input type="hidden" name="page" value="griffinforms-' . esc_attr(strtolower($this->meta)) . '">';
        echo '<input type="hidden" name="order_by" value="' . esc_attr($this->order_by) . '">';
        echo '<input type="hidden" name="order" value="' . esc_attr($this->order) . '">';
        $this->searchBox();
        
        echo '<div class="tablenav top">';
        $this->bulkActions('top');
        $this->itemFilters();
        $this->columnManagerButton();
        $this->resetFiltersBtn();
        $this->listPagination();
        echo '<br class="clear">';
        echo '</div>';

        $this->columnWidthStyles();
        echo '<table class="wp-list-table widefat fixed striped table-view-list pages">';
        $this->tableHead();
        $this->tableBody();
        $this->tableFoot();
        echo '</table>';

        echo '<div class="tablenav bottom mt-2">';
        $this->bulkActions('bottom');
        $this->listPagination();
        echo '</div>';
        
        echo '</form>';
        
        echo '</div>';
    }
    
    public function __construct()
    {
        $this->setAll();
    }
}
