(function ($) {
    'use strict';

    const roleAudiences = ['role_is', 'role_is_not'];
    const pageLocations = ['page_is', 'page_is_not'];
    const postLocations = ['post_is', 'post_is_not'];

    function escapeHtml(value) {
        return String(value)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
    }

    function pluralize(count, singular, plural) {
        return count === 1 ? singular : plural;
    }

    function getSelectedRoleNames($panel) {
        const names = [];

        $panel.find('.amr-role-checkbox:checked').each(function () {
            names.push($(this).data('role-name'));
        });

        return names;
    }

    function getContentWrapForLocation($panel, location) {
        if (pageLocations.indexOf(location) !== -1) {
            return $panel.find('.amr-pages-wrap');
        }

        if (postLocations.indexOf(location) !== -1) {
            return $panel.find('.amr-posts-wrap');
        }

        return $();
    }

    function getSelectedContentCount($wrap) {
        if (!$wrap.length) {
            return 0;
        }

        return $wrap.find('.amr-content-selected-item').length;
    }

    function updateRadioStates($panel) {
        $panel.find('.amr-radio-pill, .amr-radio-option').each(function () {
            const $label = $(this);
            $label.toggleClass('amr-is-selected', $label.find('input[type="radio"]').is(':checked'));
        });
    }

    function updateRoleList($panel) {
        const search = ($panel.find('.amr-role-search').val() || '').toString().toLowerCase().trim();
        const $options = $panel.find('.amr-role-option');
        const totalCount = $options.length;
        let matchingCount = 0;
        let selectedCount = 0;
        let hasVisibleOptions = false;

        $options.each(function () {
            const $option = $(this);
            const label = ($option.data('role-label') || '').toString();
            const checked = $option.find('.amr-role-checkbox').is(':checked');
            const matchesSearch = !search || label.indexOf(search) !== -1;

            $option.toggleClass('amr-filtered', !matchesSearch);
            $option.toggleClass('amr-is-selected', checked);

            if (matchesSearch) {
                matchingCount++;
                hasVisibleOptions = true;
            }

            if (checked) {
                selectedCount++;
            }
        });

        $panel.find('.amr-role-list').toggleClass('amr-has-no-matches', !hasVisibleOptions);

        if (search) {
            $panel.find('.amr-roles-count').text(selectedCount + ' / ' + totalCount + ' selected · ' + matchingCount + ' matching');
        } else {
            $panel.find('.amr-roles-count').text(selectedCount + ' / ' + totalCount + ' selected');
        }
    }

    function updateContentWrap($wrap) {
        if (!$wrap.length) {
            return;
        }

        const type = ($wrap.data('amr-content-type') || '').toString();
        const selectedCount = getSelectedContentCount($wrap);
        const label = type === 'page' ? pluralize(selectedCount, 'page', 'pages') : pluralize(selectedCount, 'post', 'posts');

        $wrap.find('.amr-content-count').text(selectedCount + ' ' + label + ' selected');
        $wrap.find('.amr-content-selected').toggleClass('amr-content-selected--empty', selectedCount === 0);
    }

    function updateAllContentWraps($panel) {
        $panel.find('.amr-content-wrap').each(function () {
            updateContentWrap($(this));
        });
    }

    function getAudienceText($panel) {
        const audience = $panel.find('.amr-audience:checked').val() || 'everyone';
        const roleNames = getSelectedRoleNames($panel);
        const roleCount = roleNames.length;
        let text = 'Everyone';
        let compact = 'Everyone';

        if (audience === 'logged_in') {
            text = 'Logged in';
            compact = 'Logged in';
        } else if (audience === 'logged_out') {
            text = 'Logged out';
            compact = 'Logged out';
        } else if (audience === 'role_is') {
            text = roleCount ? 'Role is · ' + roleCount + ' ' + pluralize(roleCount, 'role', 'roles') + ' selected' : 'Role is · no roles selected';
            compact = roleCount ? 'Role is · ' + roleCount + ' ' + pluralize(roleCount, 'role', 'roles') : 'Role is · no roles';
        } else if (audience === 'role_is_not') {
            text = roleCount ? 'Role is not · ' + roleCount + ' ' + pluralize(roleCount, 'role', 'roles') + ' selected' : 'Role is not · no roles selected';
            compact = roleCount ? 'Role is not · ' + roleCount + ' ' + pluralize(roleCount, 'role', 'roles') : 'Role is not · no roles';
        }

        return {
            value: audience,
            roleCount: roleCount,
            text: text,
            compact: compact
        };
    }

    function getLocationText($panel) {
        const location = $panel.find('.amr-location:checked').val() || 'everywhere';
        const $contentWrap = getContentWrapForLocation($panel, location);
        const contentCount = getSelectedContentCount($contentWrap);
        let text = 'Everywhere';
        let compact = 'Everywhere';

        if (location === 'page_is') {
            text = contentCount ? 'Page is · ' + contentCount + ' ' + pluralize(contentCount, 'page', 'pages') + ' selected' : 'Page is · no pages selected';
            compact = contentCount ? 'Page is · ' + contentCount + ' ' + pluralize(contentCount, 'page', 'pages') : 'Page is · no pages';
        } else if (location === 'page_is_not') {
            text = contentCount ? 'Page is not · ' + contentCount + ' ' + pluralize(contentCount, 'page', 'pages') + ' selected' : 'Page is not · no pages selected';
            compact = contentCount ? 'Page is not · ' + contentCount + ' ' + pluralize(contentCount, 'page', 'pages') : 'Page is not · no pages';
        } else if (location === 'post_is') {
            text = contentCount ? 'Post is · ' + contentCount + ' ' + pluralize(contentCount, 'post', 'posts') + ' selected' : 'Post is · no posts selected';
            compact = contentCount ? 'Post is · ' + contentCount + ' ' + pluralize(contentCount, 'post', 'posts') : 'Post is · no posts';
        } else if (location === 'post_is_not') {
            text = contentCount ? 'Post is not · ' + contentCount + ' ' + pluralize(contentCount, 'post', 'posts') + ' selected' : 'Post is not · no posts selected';
            compact = contentCount ? 'Post is not · ' + contentCount + ' ' + pluralize(contentCount, 'post', 'posts') : 'Post is not · no posts';
        }

        return {
            value: location,
            contentCount: contentCount,
            text: text,
            compact: compact
        };
    }

    function getRuleText($panel) {
        const action = $panel.find('.amr-action:checked').val();
        const actionText = action === 'hide' ? 'Hide' : 'Show';
        const audience = getAudienceText($panel);
        const location = getLocationText($panel);
        const isDefault = action === 'show' && audience.value === 'everyone' && location.value === 'everywhere';
        const summaryParts = [actionText, audience.text, location.text];
        const compactParts = [actionText, audience.compact, location.compact];

        return {
            action: action,
            actionText: actionText,
            audience: audience.value,
            location: location.value,
            roleCount: audience.roleCount,
            contentCount: location.contentCount,
            audienceText: audience.text,
            locationText: location.text,
            compactAudienceText: audience.compact,
            compactLocationText: location.compact,
            isDefault: isDefault,
            summary: summaryParts.join(' · '),
            compactSummary: compactParts.join(' · ')
        };
    }

    function updateRuleSummary($panel) {
        const rule = getRuleText($panel);

        $panel.find('.amr-roles-wrap').toggleClass('amr-hidden', roleAudiences.indexOf(rule.audience) === -1);
        $panel.find('.amr-pages-wrap').toggleClass('amr-hidden', pageLocations.indexOf(rule.location) === -1);
        $panel.find('.amr-posts-wrap').toggleClass('amr-hidden', postLocations.indexOf(rule.location) === -1);

        if (rule.isDefault) {
            $panel.find('.amr-summary').text('Default: shown to everyone everywhere. No custom rule will be saved.');
        } else {
            $panel.find('.amr-summary').text('Rule: ' + rule.summary);
        }
    }

    function updateMenuItemBadge($panel) {
        const rule = getRuleText($panel);
        const $menuItem = $panel.closest('.menu-item');

        if (!$menuItem.length) {
            return;
        }

        const $titleArea = $menuItem.children('.menu-item-bar').find('.item-title').first();

        if (!$titleArea.length) {
            return;
        }

        let $badge = $titleArea.children('.amr-menu-badge');

        if (rule.isDefault) {
            $badge.remove();
            return;
        }

        if (!$badge.length) {
            $badge = $('<span class="amr-menu-badge" aria-label="Titanium Nav Menu Roles & Visibility Rules summary"></span>');
            $titleArea.append($badge);
        }

        $badge
            .removeClass('amr-menu-badge--show amr-menu-badge--hide')
            .addClass(rule.action === 'hide' ? 'amr-menu-badge--hide' : 'amr-menu-badge--show')
            .attr('title', 'Titanium Nav Menu Roles & Visibility Rules: ' + rule.compactSummary)
            .text(rule.compactSummary);
    }

    function refreshPanel($panel) {
        updateRadioStates($panel);
        updateRoleList($panel);
        updateAllContentWraps($panel);
        updateRuleSummary($panel);
        updateMenuItemBadge($panel);
    }

    function initPanel(panel) {
        const $panel = $(panel);

        if ($panel.data('amr-initialized')) {
            refreshPanel($panel);
            return;
        }

        $panel.data('amr-initialized', true);
        refreshPanel($panel);
    }

    function initAllPanels(context) {
        $(context || document).find('.amr-panel').each(function () {
            initPanel(this);
        });
    }

    function preventMenuToggleDragStart(event) {
        // Keep the expand arrow clickable without letting WordPress sortable
        // treat that same down-event as the start of a drag.
        event.stopImmediatePropagation();
    }

    function improveMenuSortableTolerance() {
        const $menu = $('#menu-to-edit');

        if (!$menu.length || !$menu.data('ui-sortable')) {
            return;
        }

        try {
            // Do not use jQuery UI sortable delay here. A delay makes the menu
            // feel frozen. Instead, let the item move normally, but cancel the
            // reorder on mouseup if the press lasted less than 500ms.
            $menu.sortable('option', 'delay', 0);
            $menu.sortable('option', 'distance', 2);

            if ($menu.data('amr-sortable-wrapped')) {
                return;
            }

            const originalStart = $menu.sortable('option', 'start');
            const originalStop = $menu.sortable('option', 'stop');

            $menu.data('amr-sortable-wrapped', true);

            $menu.sortable('option', 'start', function (event, ui) {
                ui.item.data('amr-drag-start-time', Date.now());

                if (typeof originalStart === 'function') {
                    return originalStart.call(this, event, ui);
                }
            });

            $menu.sortable('option', 'stop', function (event, ui) {
                const startedAt = parseInt(ui.item.data('amr-drag-start-time'), 10) || 0;
                const elapsed = startedAt ? (Date.now() - startedAt) : 0;

                ui.item.removeData('amr-drag-start-time');

                if (elapsed && elapsed < 500) {
                    $(this).sortable('cancel');
                    return false;
                }

                if (typeof originalStop === 'function') {
                    return originalStop.call(this, event, ui);
                }
            });
        } catch (error) {
            // If WordPress changes the Menus sortable internals, do nothing.
        }
    }

    function clearContentResults($wrap) {
        $wrap.find('.amr-content-results').empty().removeClass('amr-content-results--active');
    }

    function setContentResultsMessage($wrap, message) {
        $wrap.find('.amr-content-results')
            .addClass('amr-content-results--active')
            .html('<div class="amr-content-results-message">' + escapeHtml(message) + '</div>');
    }

    function isContentSelected($wrap, id) {
        return $wrap.find('.amr-content-selected-item[data-content-id="' + id + '"]').length > 0;
    }

    function addSelectedContent($wrap, item) {
        const id = parseInt(item.id, 10);

        if (!id || isContentSelected($wrap, id)) {
            return;
        }

        const inputName = ($wrap.data('amr-input-name') || '').toString();
        const title = item.title || ('#' + id);
        const html = '' +
            '<div class="amr-content-selected-item" data-content-id="' + id + '">' +
                '<input type="hidden" name="' + escapeHtml(inputName) + '" value="' + id + '" />' +
                '<span class="amr-content-selected-title">' + escapeHtml(title) + '</span>' +
                '<span class="amr-content-selected-meta">#' + id + '</span>' +
                '<button type="button" class="button-link amr-content-remove" aria-label="Remove selected item">×</button>' +
            '</div>';

        $wrap.find('.amr-content-selected').append(html);
        clearContentResults($wrap);
        $wrap.find('.amr-content-search').val('');
        refreshPanel($wrap.closest('.amr-panel'));
    }

    function renderContentSearchResults($wrap, items) {
        const $results = $wrap.find('.amr-content-results');

        if (!items || !items.length) {
            setContentResultsMessage($wrap, (window.tiamrAdmin && tiamrAdmin.noResults) ? tiamrAdmin.noResults : 'No results found.');
            return;
        }

        let html = '<div class="amr-content-result-list">';

        items.forEach(function (item) {
            const id = parseInt(item.id, 10);
            const selected = isContentSelected($wrap, id);
            const disabledAttr = selected ? ' disabled="disabled"' : '';
            const status = item.status ? ' · ' + item.status : '';
            const typeLabel = item.label || item.type || '';

            html += '' +
                '<button type="button" class="amr-content-result" data-content-id="' + id + '" data-content-title="' + escapeHtml(item.title || '') + '"' + disabledAttr + '>' +
                    '<span class="amr-content-result-title">' + escapeHtml(item.title || ('#' + id)) + '</span>' +
                    '<span class="amr-content-result-meta">' + escapeHtml(typeLabel) + ' #' + id + escapeHtml(status) + '</span>' +
                '</button>';
        });

        html += '</div>';

        $results.addClass('amr-content-results--active').html(html);
    }

    function searchContent($wrap) {
        const search = ($wrap.find('.amr-content-search').val() || '').toString().trim();
        const postType = ($wrap.data('amr-content-type') || '').toString();

        if (search.length < 2) {
            clearContentResults($wrap);
            return;
        }

        if (!window.tiamrAdmin || !tiamrAdmin.ajaxUrl || !tiamrAdmin.searchNonce) {
            return;
        }

        setContentResultsMessage($wrap, tiamrAdmin.searching || 'Searching...');

        $.post(tiamrAdmin.ajaxUrl, {
            action: 'tiamr_search_content',
            nonce: tiamrAdmin.searchNonce,
            post_type: postType,
            search: search
        })
            .done(function (response) {
                if (!response || !response.success || !response.data) {
                    setContentResultsMessage($wrap, tiamrAdmin.noResults || 'No results found.');
                    return;
                }

                renderContentSearchResults($wrap, response.data.items || []);
            })
            .fail(function () {
                setContentResultsMessage($wrap, tiamrAdmin.noResults || 'No results found.');
            });
    }

    $(document).on('change', '.amr-audience, .amr-location, .amr-action, .amr-role-checkbox', function () {
        refreshPanel($(this).closest('.amr-panel'));
    });

    $(document).on('input', '.amr-role-search', function () {
        refreshPanel($(this).closest('.amr-panel'));
    });

    $(document).on('click', '.amr-select-all-roles', function () {
        const $panel = $(this).closest('.amr-panel');

        // This must really tick every role checkbox. It is not a selected-only filter.
        $panel.find('.amr-role-checkbox').prop('checked', true);
        refreshPanel($panel);
    });

    $(document).on('click', '.amr-clear-roles', function () {
        const $panel = $(this).closest('.amr-panel');
        $panel.find('.amr-role-checkbox').prop('checked', false);
        refreshPanel($panel);
    });

    $(document).on('input', '.amr-content-search', function () {
        const $input = $(this);
        const $wrap = $input.closest('.amr-content-wrap');
        const previousTimer = $input.data('amr-search-timer');

        if (previousTimer) {
            window.clearTimeout(previousTimer);
        }

        $input.data('amr-search-timer', window.setTimeout(function () {
            searchContent($wrap);
        }, 250));
    });

    $(document).on('click', '.amr-content-result', function () {
        const $result = $(this);

        if ($result.is(':disabled')) {
            return;
        }

        addSelectedContent($result.closest('.amr-content-wrap'), {
            id: $result.data('content-id'),
            title: $result.data('content-title')
        });
    });

    $(document).on('click', '.amr-content-remove', function () {
        const $wrap = $(this).closest('.amr-content-wrap');
        $(this).closest('.amr-content-selected-item').remove();
        refreshPanel($wrap.closest('.amr-panel'));
    });

    $(document).on('mousedown touchstart pointerdown', '.menu-item-bar .item-edit, .menu-item-bar .amr-menu-badge', preventMenuToggleDragStart);


    $(document).on('submit', '.amr-skip-import-form', function (event) {
        const sourceName = ($(this).data('source-name') || 'the old plugin').toString();
        const message = 'Are you sure you want to skip the import?\n\n' +
            'Titanium Nav Menu Roles & Visibility Rules only offers automatic import from plugins that are currently active. This helps make sure the import is based on settings from a plugin that is still in use, not old metadata left behind from a plugin that was removed months or years ago.\n\n' +
            'If you skip now and deactivate or delete ' + sourceName + ' later, automatic import may no longer be available. You may need to configure some menu items manually.\n\n' +
            'You can still continue without importing if you prefer to start from scratch.';

        if (!window.confirm(message)) {
            event.preventDefault();
        }
    });

    $(function () {
        initAllPanels(document);
        improveMenuSortableTolerance();

        // WordPress can reinitialise sortable after AJAX menu changes.
        window.setTimeout(improveMenuSortableTolerance, 300);
    });

    // WordPress fires this when a new menu item is added through AJAX.
    $(document).on('menu-item-added', function (event, menuMarkup) {
        initAllPanels(menuMarkup || document);
        window.setTimeout(improveMenuSortableTolerance, 100);
    });

})(jQuery);
