/**
 * RSL Pagination Component
 *
 * Automatically handles client-side pagination for tables with the .rsl-table class.
 * Provides keyboard-accessible controls with ARIA support and automatic page
 * state management.
 *
 * @fileoverview Client-side table pagination with accessibility support
 * @version 2.0.0
 * @license MIT
 *
 * Key Features:
 * - Automatic pagination for .rsl-table elements
 * - Configurable rows per page (default: 10)
 * - Previous/Next/First/Last navigation
 * - Numeric page links with active state
 * - ARIA attributes for screen readers
 * - Automatic disabled state management
 * - Smart pagination detection near tables
 * - FilterBus integration for auto-reset on filter changes
 *
 * Usage:
 * // Basic table with pagination (auto-initialized):
 * <table class="rsl-table">
 *   <thead>
 *     <tr><th>Header</th></tr>
 *   </thead>
 *   <tbody>
 *     <tr><td>Row 1</td></tr>
 *     <tr><td>Row 2</td></tr>
 *     <!-- More rows -->
 *   </tbody>
 * </table>
 *
 * <ul class="rsl-pagination">
 *   <li><a href="#">Previous</a></li>
 *   <li><a href="#">1</a></li>
 *   <li><a href="#">2</a></li>
 *   <li><a href="#">3</a></li>
 *   <li><a href="#">Next</a></li>
 * </ul>
 *
 * // With First/Last links:
 * <ul class="rsl-pagination">
 *   <li><a href="#">First</a></li>
 *   <li><a href="#">Previous</a></li>
 *   <li><a href="#">1</a></li>
 *   <li><a href="#">2</a></li>
 *   <li><a href="#">Next</a></li>
 *   <li><a href="#">Last</a></li>
 * </ul>
 *
 * // FilterBus Integration (auto-reset to page 1 when filters change):
 * <ul class="rsl-pagination" data-filter-subscribe="region">
 *   <!-- When region filter changes, pagination resets to page 1 -->
 * </ul>
 *
 * // Subscribe to multiple filter keys:
 * <ul class="rsl-pagination" data-filter-subscribe="region,status,dateFilter">
 *   <!-- Resets when any of these filters change -->
 * </ul>
 *
 * Public API:
 * - RSL.Pagination.init() - Initialize all pagination instances (JSON API compatible)
 * - RSL.Pagination.init(table, pagination, rowsPerPage) - Initialize specific table (backward compatible)
 * - RSL.Pagination.create(table, pagination, rowsPerPage) - Create single instance
 * - RSL.Pagination.showPage(table, pageNum) - Show specific page
 * - RSL.Pagination.getConfig() - Get current configuration
 * - RSL.Pagination.destroy(table) - Destroy pagination instance and cleanup
 * - RSL.Pagination.instances - Map of initialized instances
 *
 * JSON Layout API:
 * This component is fully compatible with the RSL JSON Layout API.
 * Tables rendered via JSON will automatically initialize pagination when
 * RSL.Pagination.init() is called (automatic in JSON rendering).
 */

(function() {
    'use strict';

    // Initialize RSL namespace
    window.RSL = window.RSL || {};

    /**
     * Default configuration
     * @const
     * @type {Object}
     */
    const DEFAULT_CONFIG = {
        ROWS_PER_PAGE: 10,
        TABLE_SELECTOR: '.rsl-table',
        PAGINATION_SELECTOR: '.rsl-pagination'
    };

    /**
     * Track initialized table instances to prevent double-initialization
     * @type {Map<HTMLElement, Object>}
     */
    const instances = new Map();

    /**
     * Track FilterBus subscriptions for cleanup
     * @type {Map<HTMLElement, string>}
     */
    const filterSubscriptions = new Map();

    /**
     * Setup FilterBus subscription for a pagination element
     * When any subscribed filter changes, pagination resets to page 1
     * @param {HTMLElement} pagination - The pagination element
     * @param {HTMLElement} table - The associated table element
     */
    function setupFilterBusSubscription(pagination, table) {
        // Check if FilterBus is available
        if (!window.RSL || !window.RSL.FilterBus) {
            return;
        }

        // Check if this pagination has filter subscription configured
        var filterSubscribe = pagination.getAttribute('data-filter-subscribe');
        if (!filterSubscribe) {
            return;
        }

        // Don't double-subscribe
        if (filterSubscriptions.has(pagination)) {
            return;
        }

        // Parse subscription keys (support comma-separated)
        var subscribeKeys = filterSubscribe.split(',').map(function(k) {
            return k.trim();
        }).filter(function(k) {
            return k.length > 0;
        });

        if (subscribeKeys.length === 0) {
            return;
        }

        // Generate unique subscriber ID
        var subscriberId = 'pagination-' + (pagination.id || Math.random().toString(36).substr(2, 9));

        // Subscribe to FilterBus
        window.RSL.FilterBus.subscribe(
            subscriberId,
            function(state, meta) {
                handleFilterBusChange(pagination, table, state, meta);
            },
            { keys: subscribeKeys }
        );

        // Store subscription ID for cleanup
        filterSubscriptions.set(pagination, subscriberId);
    }

    /**
     * Handle FilterBus state changes - reset pagination to page 1
     * @param {HTMLElement} pagination - The pagination element
     * @param {HTMLElement} table - The associated table element
     * @param {Object} state - Current filter state
     * @param {Object} meta - Change metadata
     */
    function handleFilterBusChange(pagination, table, state, meta) {
        // Skip reset on initial state load
        if (meta && meta.source === 'init') {
            return;
        }

        // Get current page
        var currentPage = getCurrentPage(pagination);

        // Only reset if not already on page 1
        if (currentPage !== 1) {
            // Reset to page 1
            var tbody = table.querySelector('tbody');
            if (tbody) {
                var allRows = Array.from(tbody.querySelectorAll('tr'));
                if (allRows.length > 0) {
                    showPage(table, allRows, 1);
                    updateActiveState(pagination, 1);
                }
            }

            // Dispatch event
            pagination.dispatchEvent(new CustomEvent('rsl-pagination:filterbus-reset', {
                bubbles: true,
                detail: { state: state, meta: meta, previousPage: currentPage }
            }));
        }
    }

    /**
     * Cleanup FilterBus subscription for a pagination element
     * @param {HTMLElement} pagination - The pagination element
     */
    function cleanupFilterBusSubscription(pagination) {
        var subscriberId = filterSubscriptions.get(pagination);
        if (subscriberId && window.RSL && window.RSL.FilterBus && window.RSL.FilterBus.unsubscribe) {
            window.RSL.FilterBus.unsubscribe(subscriberId);
        }
        filterSubscriptions.delete(pagination);
    }

    /**
     * Create pagination for a specific table
     *
     * Sets up pagination controls for a table, hiding rows beyond the first page
     * and attaching click handlers to pagination links.
     *
     * @param {HTMLElement} table - The table element to paginate
     * @param {HTMLElement} pagination - The pagination controls element
     * @param {number} [rowsPerPage=10] - Number of rows to show per page
     *
     * @example
     * const table = document.querySelector('.rsl-table');
     * const pagination = document.querySelector('.rsl-pagination');
     * RSL.Pagination.create(table, pagination, 20);
     */
    function createPagination(table, pagination, rowsPerPage = DEFAULT_CONFIG.ROWS_PER_PAGE) {
        // Prevent double-initialization
        if (instances.has(table)) {
            return instances.get(table);
        }
        const tbody = table.querySelector('tbody');
        if (!tbody) return;

        const allRows = Array.from(tbody.querySelectorAll('tr'));
        if (allRows.length === 0) return;

        // Store rows per page as data attribute
        table.dataset.rowsPerPage = rowsPerPage;

        showPage(table, allRows, 1);
        updateActiveState(pagination, 1);

        pagination.addEventListener('click', function(e) {
            e.preventDefault();

            const target = e.target.closest('a');
            if (!target) return;

            const pageNum = getPageNumber(target, pagination);
            if (pageNum) {
                showPage(table, allRows, pageNum);
                updateActiveState(pagination, pageNum);
            }
        });

        // Setup FilterBus subscription if configured
        setupFilterBusSubscription(pagination, table);

        // Store instance
        const instance = {
            table: table,
            pagination: pagination,
            rowsPerPage: rowsPerPage
        };
        instances.set(table, instance);

        return instance;
    }

    /**
     * Destroy pagination instance and cleanup resources
     *
     * @param {HTMLElement} table - The table element
     */
    function destroyPagination(table) {
        const instance = instances.get(table);
        if (!instance) return;

        // Cleanup FilterBus subscription
        if (instance.pagination) {
            cleanupFilterBusSubscription(instance.pagination);
        }

        // Remove from instances
        instances.delete(table);
    }

    /**
     * Get page number from clicked link
     *
     * Parses the clicked link text to determine which page to show.
     * Handles numeric pages, Previous/Next, and First/Last controls.
     *
     * @param {HTMLElement} link - The clicked link element
     * @param {HTMLElement} pagination - The pagination controls element
     * @returns {number|null} Page number to show, or null if invalid
     *
     * @example
     * const pageNum = getPageNumber(link, pagination);
     * if (pageNum) showPage(table, rows, pageNum);
     */
    function getPageNumber(link, pagination) {
        const text = link.textContent.trim();

        const num = parseInt(text, 10);
        if (!isNaN(num)) return num;

        const currentPage = getCurrentPage(pagination);
        const totalPages = getTotalPages(pagination);

        if (text.toLowerCase().includes('prev')) {
            return currentPage > 1 ? currentPage - 1 : null;
        }
        if (text.toLowerCase().includes('next')) {
            return currentPage < totalPages ? currentPage + 1 : null;
        }

        if (text.toLowerCase().includes('first')) return 1;
        if (text.toLowerCase().includes('last')) return totalPages;

        return null;
    }

    /**
     * Get current active page number
     *
     * Reads the active page number from pagination controls by finding
     * the link with the .active class.
     *
     * @param {HTMLElement} pagination - The pagination controls element
     * @returns {number} Current page number (defaults to 1)
     *
     * @example
     * const currentPage = getCurrentPage(pagination);
     * console.log(`Currently on page ${currentPage}`);
     */
    function getCurrentPage(pagination) {
        const active = pagination.querySelector('.active a');
        if (active) {
            const num = parseInt(active.textContent, 10);
            if (!isNaN(num)) return num;
        }
        return 1;
    }

    /**
     * Get total number of pages from pagination links
     *
     * Scans all pagination links and finds the highest numeric page number.
     *
     * @param {HTMLElement} pagination - The pagination controls element
     * @returns {number} Total number of pages
     *
     * @example
     * const totalPages = getTotalPages(pagination);
     * console.log(`Total pages: ${totalPages}`);
     */
    function getTotalPages(pagination) {
        const pageLinks = pagination.querySelectorAll('a');
        let maxPage = 1;

        pageLinks.forEach(function(link) {
            const num = parseInt(link.textContent, 10);
            if (!isNaN(num) && num > maxPage) {
                maxPage = num;
            }
        });

        return maxPage;
    }

    /**
     * Show specific page of table rows
     *
     * Displays rows for the specified page and hides all other rows.
     * Uses the rowsPerPage value stored in the table's data attribute.
     *
     * @param {HTMLElement} table - The table element
     * @param {Array<HTMLElement>} rows - Array of all table rows
     * @param {number} pageNum - Page number to show (1-indexed)
     *
     * @example
     * const rows = Array.from(tbody.querySelectorAll('tr'));
     * showPage(table, rows, 2); // Show second page
     */
    function showPage(table, rows, pageNum) {
        const rowsPerPage = parseInt(table.dataset.rowsPerPage, 10) || DEFAULT_CONFIG.ROWS_PER_PAGE;
        const startRow = (pageNum - 1) * rowsPerPage;
        const endRow = startRow + rowsPerPage;

        rows.forEach(function(row, i) {
            row.style.display = (i >= startRow && i < endRow) ? '' : 'none';
        });
    }

    /**
     * Update active state on pagination links
     *
     * Adds .active class to current page link, updates aria-current attribute,
     * and manages disabled states for navigation controls.
     *
     * @param {HTMLElement} pagination - The pagination controls element
     * @param {number} pageNum - Current page number
     *
     * @example
     * updateActiveState(pagination, 3);
     * // Page 3 link now has .active class and aria-current="page"
     */
    function updateActiveState(pagination, pageNum) {
        const allItems = pagination.querySelectorAll('li');
        allItems.forEach(function(item) {
            item.classList.remove('active');
        });

        const links = pagination.querySelectorAll('a');
        links.forEach(function(link) {
            if (parseInt(link.textContent, 10) === pageNum) {
                link.parentElement.classList.add('active');
                link.setAttribute('aria-current', 'page');
            } else {
                link.removeAttribute('aria-current');
            }
        });

        updateDisabledStates(pagination, pageNum);
    }

    /**
     * Update disabled states for navigation buttons
     *
     * Disables Previous/First buttons on first page and Next/Last buttons
     * on last page. Adds .disabled class and aria-disabled attribute.
     *
     * @param {HTMLElement} pagination - The pagination controls element
     * @param {number} currentPage - Current page number
     *
     * @example
     * updateDisabledStates(pagination, 1);
     * // Previous and First links are now disabled
     */
    function updateDisabledStates(pagination, currentPage) {
        const totalPages = getTotalPages(pagination);
        const links = pagination.querySelectorAll('a');

        links.forEach(function(link) {
            const text = link.textContent.trim().toLowerCase();
            const li = link.parentElement;

            if (text.includes('prev') || text.includes('first')) {
                if (currentPage === 1) {
                    li.classList.add('disabled');
                    link.setAttribute('aria-disabled', 'true');
                } else {
                    li.classList.remove('disabled');
                    link.removeAttribute('aria-disabled');
                }
            }

            if (text.includes('next') || text.includes('last')) {
                if (currentPage === totalPages) {
                    li.classList.add('disabled');
                    link.setAttribute('aria-disabled', 'true');
                } else {
                    li.classList.remove('disabled');
                    link.removeAttribute('aria-disabled');
                }
            }
        });
    }

    /**
     * Auto-initialize all tables with pagination
     *
     * Finds all tables with .rsl-table class, locates their associated
     * pagination controls, and initializes pagination for each pair.
     *
     * @example
     * // Called automatically on DOMContentLoaded
     * // Can be called manually after dynamic content:
     * autoInit();
     */
    function autoInit() {
        const tables = document.querySelectorAll(DEFAULT_CONFIG.TABLE_SELECTOR);

        tables.forEach(function(table) {
            const pagination = findNearestPagination(table);
            if (pagination) {
                // Read rows per page from data-paginate attribute, or use default
                var rowsPerPage = parseInt(table.getAttribute('data-paginate'), 10) || DEFAULT_CONFIG.ROWS_PER_PAGE;
                createPagination(table, pagination, rowsPerPage);
            }
        });
    }

    /**
     * Find nearest pagination element to a table
     *
     * Searches for pagination controls in the same parent container
     * or among sibling elements following the table.
     *
     * @param {HTMLElement} table - The table element
     * @returns {HTMLElement|null} Pagination element or null if not found
     *
     * @example
     * const pagination = findNearestPagination(table);
     * if (pagination) {
     *   initPagination(table, pagination);
     * }
     */
    function findNearestPagination(table) {
        const parent = table.closest('.demo-section, .demo-wrap, .slot-item, .container');
        if (parent) {
            const pagination = parent.querySelector(DEFAULT_CONFIG.PAGINATION_SELECTOR);
            if (pagination) return pagination;
        }

        let sibling = table.nextElementSibling;
        while (sibling) {
            const pagination = sibling.querySelector ? sibling.querySelector(DEFAULT_CONFIG.PAGINATION_SELECTOR) : null;
            if (pagination) return pagination;
            if (sibling.classList && sibling.classList.contains('rsl-pagination')) return sibling;
            sibling = sibling.nextElementSibling;
        }

        return null;
    }

    /**
     * Public API
     *
     * @namespace RSL.Pagination
     * @property {Function} init - Initialize all pagination instances OR specific table (backward compatible)
     * @property {Function} create - Create pagination for specific table
     * @property {Function} showPage - Show specific page of table
     * @property {Function} getConfig - Get current configuration
     * @property {Map} instances - Map of initialized table instances
     */
    window.RSL.Pagination = {
        /**
         * Track initialized instances
         */
        instances: instances,

        /**
         * Initialize all pagination instances on the page OR a specific table (backward compatible)
         *
         * When called with no arguments: Scans for all .rsl-table elements and initializes pagination
         * When called with arguments: Initializes specific table (backward compatible with v1.0.0)
         *
         * @param {HTMLElement} [table] - Optional: specific table element (backward compatible)
         * @param {HTMLElement} [pagination] - Optional: pagination controls element (backward compatible)
         * @param {number} [rowsPerPage=10] - Optional: rows per page (backward compatible)
         *
         * @example
         * // JSON API compatible - Initialize all instances:
         * RSL.Pagination.init();
         *
         * @example
         * // Backward compatible - Initialize specific table:
         * const table = document.querySelector('.rsl-table');
         * const pagination = document.querySelector('.rsl-pagination');
         * RSL.Pagination.init(table, pagination, 20);
         */
        init: function(table, pagination, rowsPerPage) {
            // New behavior: No arguments = scan for all instances (JSON API compatible)
            if (!table) {
                autoInit();
                return;
            }

            // Backward compatible: Initialize specific table
            return createPagination(table, pagination, rowsPerPage);
        },

        /**
         * Create pagination for a specific table
         *
         * @param {HTMLElement} table - The table element
         * @param {HTMLElement} pagination - The pagination controls element
         * @param {number} [rowsPerPage=10] - Number of rows per page
         * @returns {Object} Instance object
         *
         * @example
         * const table = document.querySelector('.rsl-table');
         * const pagination = document.querySelector('.rsl-pagination');
         * RSL.Pagination.create(table, pagination, 20);
         */
        create: createPagination,

        /**
         * Show a specific page of table rows
         *
         * @param {HTMLElement} table - The table element
         * @param {number} pageNum - Page number to show
         *
         * @example
         * const table = document.querySelector('.rsl-table');
         * RSL.Pagination.showPage(table, 3);
         */
        showPage: function(table, pageNum) {
            const tbody = table.querySelector('tbody');
            if (!tbody) return;

            const allRows = Array.from(tbody.querySelectorAll('tr'));
            if (allRows.length === 0) return;

            showPage(table, allRows, pageNum);

            const pagination = findNearestPagination(table);
            if (pagination) {
                updateActiveState(pagination, pageNum);
            }
        },

        /**
         * Get current configuration
         *
         * @returns {Object} Configuration object with ROWS_PER_PAGE, TABLE_SELECTOR, PAGINATION_SELECTOR
         *
         * @example
         * const config = RSL.Pagination.getConfig();
         * console.log(config.ROWS_PER_PAGE); // 10
         */
        getConfig: function() {
            return Object.assign({}, DEFAULT_CONFIG);
        },

        /**
         * Destroy pagination instance and cleanup resources
         *
         * @param {HTMLElement} table - The table element
         *
         * @example
         * const table = document.querySelector('.rsl-table');
         * RSL.Pagination.destroy(table);
         */
        destroy: destroyPagination
    };

    /**
     * Auto-initialize on DOM ready or immediately if already loaded
     */
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', autoInit);
    } else {
        autoInit();
    }

})();
