<?php
/**
 * Frontend functionality for Maca Menu List
 *
 * @package Maca_Menu_List
 * @since 1.0.0
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

class Maca_Menu_List_Frontend {

    /**
     * Whether frontend assets were registered this request.
     *
     * @var bool
     */
    private static $frontend_assets_registered = false;

    /**
     * Whether a menu list shortcode/block rendered this request.
     *
     * @var bool
     */
    private static $menu_list_rendered = false;

    /**
     * Frontend singleton for late asset registration from blocks.
     *
     * @var self|null
     */
    private static $instance = null;

    public static function instance() {
        return self::$instance instanceof self ? self::$instance : null;
    }

    /**
     * Constructor
     */
    public function __construct() {
        self::$instance = $this;

        add_shortcode('maca_menu_list', array($this, 'render_shortcode'));
        add_shortcode('maca_takeaway_menu', array($this, 'render_takeaway_shortcode'));
        add_shortcode('maca_table_booking', array($this, 'render_table_booking_shortcode'));
        add_shortcode('maca_opening_hours', array($this, 'render_opening_hours_shortcode'));
        add_action('wp_ajax_maca_load_category_menu', array($this, 'ajax_load_category_menu'));
        add_action('wp_ajax_nopriv_maca_load_category_menu', array($this, 'ajax_load_category_menu'));
        add_action('wp_ajax_maca_rate_dish', array($this, 'ajax_rate_dish'));
        add_action('wp_ajax_nopriv_maca_rate_dish', array($this, 'ajax_rate_dish'));
        add_action('wp_ajax_maca_track_dish_view', array($this, 'ajax_track_dish_view'));
        add_action('wp_ajax_nopriv_maca_track_dish_view', array($this, 'ajax_track_dish_view'));
        add_action('wp_ajax_maca_submit_table_order', array($this, 'ajax_submit_table_order'));
        add_action('wp_ajax_nopriv_maca_submit_table_order', array($this, 'ajax_submit_table_order'));
        add_action('wp_ajax_maca_get_staff_orders', array($this, 'ajax_get_staff_orders'));
        add_action('wp_ajax_nopriv_maca_get_staff_orders', array($this, 'ajax_get_staff_orders'));
        add_action('wp_ajax_maca_handle_staff_order', array($this, 'ajax_handle_staff_order'));
        add_action('wp_ajax_nopriv_maca_handle_staff_order', array($this, 'ajax_handle_staff_order'));
        add_action('wp_ajax_maca_update_staff_order_status', array($this, 'ajax_update_staff_order_status'));
        add_action('wp_ajax_nopriv_maca_update_staff_order_status', array($this, 'ajax_update_staff_order_status'));
        add_action('wp_ajax_maca_update_staff_order_table', array($this, 'ajax_update_staff_order_table'));
        add_action('wp_ajax_nopriv_maca_update_staff_order_table', array($this, 'ajax_update_staff_order_table'));
        add_action('wp_ajax_maca_get_guest_order_status', array($this, 'ajax_get_guest_order_status'));
        add_action('wp_ajax_nopriv_maca_get_guest_order_status', array($this, 'ajax_get_guest_order_status'));
        add_action('wp_ajax_maca_get_booking_slots', array($this, 'ajax_get_booking_slots'));
        add_action('wp_ajax_nopriv_maca_get_booking_slots', array($this, 'ajax_get_booking_slots'));
        add_action('wp_ajax_maca_get_booking_tables', array($this, 'ajax_get_booking_tables'));
        add_action('wp_ajax_nopriv_maca_get_booking_tables', array($this, 'ajax_get_booking_tables'));
        add_action('wp_ajax_maca_submit_table_booking', array($this, 'ajax_submit_table_booking'));
        add_action('wp_ajax_nopriv_maca_submit_table_booking', array($this, 'ajax_submit_table_booking'));
        add_action('wp_ajax_maca_submit_table_booking_waitlist', array($this, 'ajax_submit_table_booking_waitlist'));
        add_action('wp_ajax_nopriv_maca_submit_table_booking_waitlist', array($this, 'ajax_submit_table_booking_waitlist'));
        add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_scripts'));
        add_filter('render_block', array($this, 'register_assets_for_menu_block'), 10, 2);
        add_action('wp_footer', array($this, 'ensure_frontend_assets_in_footer'), 1);
        add_action('wp_footer', array($this, 'print_frontend_assets_in_footer'), 20);
        add_action('init', array($this, 'maybe_handle_staff_orders_post'), 1);
        add_action('template_redirect', array($this, 'maybe_handle_staff_orders_post'), -1);
        add_action('template_redirect', array($this, 'handle_staff_orders_page'), 0);
        add_action('template_redirect', array($this, 'handle_qr_menu_page'), 1);
        add_action('template_redirect', array($this, 'handle_takeaway_menu_page'), 1);
        add_action('template_redirect', array($this, 'handle_booking_cancel_page'), 2);
    }

    /**
     * Valid website menu display modes.
     */
    private function get_allowed_display_modes() {
        return array('inline', 'popup', 'new_page');
    }

    /**
     * Current menu display mode from settings.
     */
    private function get_display_mode() {
        $mode = get_option('maca_menulist_display_mode', 'inline');
        if (!in_array($mode, $this->get_allowed_display_modes(), true)) {
            return 'inline';
        }
        return $mode;
    }

    /**
     * JS config for category menu loading on the website.
     *
     * @return array<string, mixed>
     */
    private function get_frontend_script_config() {
        return array(
            'ajaxUrl' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('maca_menu_nonce'),
            'displayMode' => $this->get_display_mode(),
            'showMenuTitle' => maca_menulist_show_menu_title(),
            'strings' => array(
                'loading' => __('Loading menu...', 'maca-restu-pro'),
                'noMenu' => __('No active menu available for this category.', 'maca-restu-pro'),
                'error' => __('Error loading menu.', 'maca-restu-pro'),
                'selectCategory' => __('Select a category to view the menu', 'maca-restu-pro'),
            ),
        );
    }

    /**
     * Inline config so category clicks work even when scripts enqueue late.
     */
    private function print_frontend_script_config_once() {
        static $printed = false;

        if ($printed) {
            return;
        }

        $printed = true;

        echo '<script>window.macaMenulist=window.macaMenulist||';
        echo wp_json_encode($this->get_frontend_script_config());
        echo ';</script>';
    }

    /**
     * Register scripts when shortcode/block is on the page (also called from wp_enqueue_scripts).
     */
    public function register_frontend_assets() {
        if (self::$frontend_assets_registered) {
            return;
        }
        self::$frontend_assets_registered = true;

        if (!wp_style_is('maca-menulist-style', 'registered')) {
            wp_register_style(
                'maca-menulist-style',
                MACA_MENULIST_PLUGIN_URL . 'assets/css/style.css',
                array(),
                MACA_MENULIST_VERSION
            );
        }

        wp_enqueue_style('maca-menulist-style');

        if (function_exists('maca_menulist_pro_has_feature') && maca_menulist_pro_has_feature('table_bookings')) {
            maca_menulist_register_table_booking_assets();
        }

        if (maca_menulist_is_public_dishes_mode()) {
            wp_enqueue_script(
                'maca-menulist-dish-menu',
                MACA_MENULIST_PLUGIN_URL . 'assets/js/dish-menu.js',
                array(),
                MACA_MENULIST_VERSION,
                true
            );

            wp_localize_script(
                'maca-menulist-dish-menu',
                'macaMenulistDish',
                maca_menulist_get_dish_menu_script_config()
            );

            if (maca_menulist_table_order_enabled()) {
                wp_enqueue_script(
                    'maca-menulist-table-order',
                    MACA_MENULIST_PLUGIN_URL . 'assets/js/table-order.js',
                    array(),
                    MACA_MENULIST_VERSION,
                    true
                );
                wp_localize_script(
                    'maca-menulist-table-order',
                    'macaMenulistTableOrder',
                    maca_menulist_get_table_order_script_config(
                        function_exists('maca_menulist_resolve_guest_order_channel')
                            ? maca_menulist_resolve_guest_order_channel()
                            : 'website'
                    )
                );
            }
        } else {
            wp_enqueue_script(
                'maca-menulist-pdf',
                MACA_MENULIST_PLUGIN_URL . 'assets/js/maca-pdf.js',
                array(),
                MACA_MENULIST_VERSION,
                true
            );

            wp_localize_script('maca-menulist-pdf', 'macaMenulistPdfConfig', array(
                'pdfLibUrl' => MACA_MENULIST_PLUGIN_URL . 'assets/vendor/pdfjs/pdf.min.js',
                'workerUrl' => MACA_MENULIST_PLUGIN_URL . 'assets/vendor/pdfjs/pdf.worker.min.js',
                'showMenuTitle' => maca_menulist_show_menu_title(),
            ));
        }

        $frontend_deps = array();
        if (!maca_menulist_is_public_dishes_mode()) {
            $frontend_deps[] = 'maca-menulist-pdf';
        }

        wp_enqueue_script(
            'maca-menulist-frontend',
            MACA_MENULIST_PLUGIN_URL . 'assets/js/frontend.js',
            $frontend_deps,
            MACA_MENULIST_VERSION,
            true
        );

        wp_localize_script('maca-menulist-frontend', 'macaMenulist', $this->get_frontend_script_config());
    }

    /**
     * Register frontend assets from block callbacks and other late render paths.
     */
    public static function ensure_frontend_assets() {
        if (self::$instance instanceof self) {
            self::$menu_list_rendered = true;
            self::$instance->register_frontend_assets();
        }
    }

    /**
     * Enqueue frontend scripts and styles when the menu is present on the page.
     */
    public function enqueue_frontend_scripts() {
        if (is_admin()) {
            return;
        }

        if ($this->page_has_menu_list()) {
            $this->register_frontend_assets();
        }
    }

    /**
     * Ensure assets are registered when a menu block renders (FSE templates, widgets, etc.).
     *
     * @param string   $block_content Rendered block HTML.
     * @param array<string, mixed> $block Parsed block data.
     * @return string
     */
    public function register_assets_for_menu_block($block_content, $block) {
        if (!is_array($block) || empty($block['blockName'])) {
            return $block_content;
        }

        $menu_blocks = array(
            'maca-restu/maca-menu-list',
            'maca-restu/menu-list',
            'maca-menulist/maca-menu-list',
            'maca-menulist/menu-list',
        );

        if (!in_array($block['blockName'], $menu_blocks, true)) {
            return $block_content;
        }

        self::$menu_list_rendered = true;
        $this->register_frontend_assets();

        return $block_content;
    }

    /**
     * Late fallback so scripts still load if the block rendered after wp_enqueue_scripts.
     */
    public function ensure_frontend_assets_in_footer() {
        if (!self::$menu_list_rendered) {
            return;
        }

        $this->register_frontend_assets();
    }

    /**
     * Print menu scripts when they were enqueued during content render (block/FSE themes).
     */
    public function print_frontend_assets_in_footer() {
        if (!self::$menu_list_rendered) {
            return;
        }

        $handles = array('maca-menulist-frontend');

        if (!maca_menulist_is_public_dishes_mode()) {
            $handles[] = 'maca-menulist-pdf';
        }

        foreach ($handles as $handle) {
            if (wp_script_is($handle, 'registered') && !wp_script_is($handle, 'done')) {
                wp_enqueue_script($handle);
            }
        }

        if (wp_script_is('maca-menulist-frontend', 'enqueued') && !wp_script_is('maca-menulist-frontend', 'done')) {
            wp_print_scripts($handles);
        }
    }

    /**
     * Detect shortcode or block in content that will show the public menu list.
     */
    private function page_has_menu_list() {
        if (self::$menu_list_rendered) {
            return true;
        }

        global $post;

        if ($post instanceof WP_Post && $this->content_has_menu_list($post->post_content)) {
            return true;
        }

        foreach ($this->get_template_contents_for_request() as $content) {
            if ($this->content_has_menu_list($content)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Whether a content string contains the menu list shortcode or block.
     *
     * @param string $content Post or template content.
     * @return bool
     */
    private function content_has_menu_list($content) {
        if (!is_string($content) || $content === '') {
            return false;
        }

        if (
            has_shortcode($content, 'maca_menu_list')
            || has_shortcode($content, 'maca_takeaway_menu')
        ) {
            return true;
        }

        if (function_exists('has_block') && (
            has_block('maca-restu/maca-menu-list', $content)
            || has_block('maca-restu/menu-list', $content)
            || has_block('maca-menulist/maca-menu-list', $content)
            || has_block('maca-menulist/menu-list', $content)
        )) {
            return true;
        }

        return false;
    }

    /**
     * Block template content for the current front-end request (FSE themes).
     *
     * @return array<int, string>
     */
    private function get_template_contents_for_request() {
        if (!function_exists('get_block_template')) {
            return array();
        }

        $template_slugs = array();

        if (is_front_page() && is_home()) {
            $template_slugs[] = 'home';
        } elseif (is_front_page()) {
            $template_slugs[] = 'front-page';
        } elseif (is_home()) {
            $template_slugs[] = 'home';
        } elseif (is_singular()) {
            $template_slugs[] = 'singular';

            if (is_page()) {
                $template_slugs[] = 'page';
                $post = get_queried_object();

                if ($post instanceof WP_Post && $post->post_name !== '') {
                    $template_slugs[] = 'page-' . $post->post_name;
                }
            } elseif (is_single()) {
                $post = get_queried_object();

                if ($post instanceof WP_Post) {
                    $template_slugs[] = 'single-' . $post->post_type;
                    if ($post->post_name !== '') {
                        $template_slugs[] = 'single-' . $post->post_type . '-' . $post->post_name;
                    }
                }
            }
        } elseif (is_archive()) {
            $template_slugs[] = 'archive';
        } elseif (is_search()) {
            $template_slugs[] = 'search';
        } elseif (is_404()) {
            $template_slugs[] = '404';
        }

        $template_slugs[] = 'index';

        $contents = array();
        $theme = get_stylesheet();

        foreach (array_unique($template_slugs) as $slug) {
            $template = get_block_template($theme . '//' . $slug, 'wp_template');

            if ($template instanceof WP_Block_Template && !empty($template->content)) {
                $contents[] = (string) $template->content;
            }
        }

        return $contents;
    }

    /**
     * Open wrapper with display mode for JS (avoids stale cached script settings).
     */
    private function open_menu_wrapper() {
        self::$menu_list_rendered = true;
        $this->register_frontend_assets();
        $this->print_frontend_script_config_once();
        echo '<div class="maca-menulist-wrap" data-display-mode="' . esc_attr($this->get_display_mode()) . '">';
        if (function_exists('maca_menulist_get_website_menu_page_title')) {
            echo '<h2 class="maca-menu-page-title maca-menu-title">' . esc_html(maca_menulist_get_website_menu_page_title()) . '</h2>';
        }
        if (!maca_menulist_is_public_dishes_mode()) {
            maca_menulist_render_menu_language_switcher(array('context' => 'inline'));
        }
    }

    /**
     * Close menu wrapper.
     */
    private function close_menu_wrapper() {
        echo '</div>';
    }

    /**
     * Output popup/inline containers for the configured display mode.
     */
    private function render_display_mode_containers() {
        $display_mode = $this->get_display_mode();

        if ($display_mode === 'inline') {
            echo '<div class="maca-menu-display" id="maca-menu-display">';
            echo '<p class="maca-menu-placeholder">' . esc_html__('Select a category to view the menu', 'maca-restu-pro') . '</p>';
            echo '</div>';
            echo '<button type="button" id="maca-menu-close" class="maca-menu-close" aria-label="' . esc_attr__('Close menu', 'maca-restu-pro') . '" style="display: none;">&times;</button>';
            return;
        }

        if ($display_mode === 'popup') {
            echo '<div class="maca-menu-popup" id="maca-menu-popup">';
            echo '<button type="button" id="maca-menu-close" class="maca-menu-close maca-menu-close--popup" aria-label="' . esc_attr__('Close menu', 'maca-restu-pro') . '">&times;</button>';
            echo '<div class="maca-popup-content" id="maca-popup-content">';
            echo '<p class="maca-menu-placeholder">' . esc_html__('Select a category to view the menu', 'maca-restu-pro') . '</p>';
            echo '</div>';
            echo '</div>';
            echo '<div class="maca-popup-overlay" id="maca-popup-overlay"></div>';
        }
    }
    
    /**
     * Render shortcode
     */
    public function render_shortcode($atts) {
        if (function_exists('maca_menulist_legal_blocks_frontend') && maca_menulist_legal_blocks_frontend()) {
            return maca_menulist_legal_frontend_blocked_message();
        }

        $atts = shortcode_atts(array(
            'category' => '',
            'buttons' => 'true',
            'show_all' => 'false',
        ), $atts, 'maca_menu_list');

        ob_start();
        $this->open_menu_wrapper();

        if (maca_menulist_is_public_dishes_mode()) {
            // Website menu is view-only; ordering is available on the QR menu page.
            maca_menulist_render_dish_menu('inline', false);
            $this->close_menu_wrapper();
            return ob_get_clean();
        }

        if (!empty($atts['category'])) {
            $category_id = $this->get_category_id_by_name($atts['category']);
            if ($category_id > 0) {
                $this->render_single_category_button($category_id);
            } else {
                echo '<p>' . esc_html__('Category not found.', 'maca-restu-pro') . '</p>';
            }
        } elseif ($atts['buttons'] === 'true') {
            $this->render_category_buttons();
        } elseif ($atts['show_all'] === 'true') {
            $this->render_all_categories_with_menus();
        } else {
            // List view: vertical buttons, respects popup / new page / inline setting.
            $this->render_category_buttons('vertical');
        }

        $this->close_menu_wrapper();

        return ob_get_clean();
    }

    /**
     * Shortcode: takeaway menu with ordering (same schedule as QR).
     *
     * @return string
     */
    public function render_takeaway_shortcode() {
        if (function_exists('maca_menulist_legal_blocks_frontend') && maca_menulist_legal_blocks_frontend()) {
            return maca_menulist_legal_frontend_blocked_message();
        }

        if (!maca_menulist_is_public_dishes_mode() || !maca_menulist_takeaway_ordering_enabled()) {
            return '<p>' . esc_html__('Takeaway ordering is not available.', 'maca-restu-pro') . '</p>';
        }

        maca_menulist_set_guest_order_channel('takeaway');
        $this->register_frontend_assets();

        ob_start();
        $this->open_menu_wrapper();
        maca_menulist_render_dish_menu('takeaway', true);
        $this->close_menu_wrapper();
        return ob_get_clean();
    }
    
    /**
     * Render category buttons with thumbnails
     */
    private function render_category_buttons($layout_override = null) {
        $categories = maca_menulist_db_get_categories(true);

        $button_layout = $layout_override !== null
            ? $layout_override
            : get_option('maca_menulist_button_layout', 'horizontal');

        $categories = maca_menulist_filter_categories_with_published_menus($categories);

        if (empty($categories)) {
            echo '<p>' . esc_html__('No menu categories available.', 'maca-restu-pro') . '</p>';
            return;
        }

        $use_compact_filters = in_array($button_layout, array('horizontal', 'fit_width'), true);
        $buttons_class = 'maca-category-buttons layout-' . esc_attr($button_layout);
        if ($use_compact_filters) {
            $buttons_class .= ' maca-filter-bar';
        }

        echo '<div class="' . esc_attr($buttons_class) . '">';

        foreach ($categories as $category) {
            maca_menulist_normalize_category($category);
            $thumbnail = $category->thumbnail_url ? esc_url($category->thumbnail_url) : '';
            $category_label = maca_menulist_get_category_display_name($category);

            echo '<button type="button" class="maca-category-button" data-category-id="' . esc_attr($category->id) . '">';
            echo '<div class="maca-category-button-content">';
            if ($thumbnail) {
                echo '<img src="' . esc_url($category->thumbnail_url) . '" alt="' . esc_attr($category_label) . '" class="maca-category-thumbnail">';
            }
            echo '<span class="maca-category-name">' . esc_html($category_label) . '</span>';
            echo '</div>';
            echo '</button>';
        }

        echo '</div>';
        $this->render_display_mode_containers();
    }

    /**
     * One category button (shortcode category="Name") – uses global display mode.
     */
    private function render_single_category_button($category_id) {
        $category = maca_menulist_db_get_category($category_id);

        if (!$category) {
            echo '<p>' . esc_html__('Category not found.', 'maca-restu-pro') . '</p>';
            return;
        }

        maca_menulist_normalize_category($category);
        $thumbnail = $category->thumbnail_url ? esc_url($category->thumbnail_url) : '';
        $category_label = maca_menulist_get_category_display_name($category);

        echo '<div class="maca-category-buttons layout-horizontal maca-category-buttons-single">';
        echo '<button type="button" class="maca-category-button" data-category-id="' . esc_attr($category->id) . '">';
        echo '<div class="maca-category-button-content">';
            if ($thumbnail) {
                echo '<img src="' . esc_url($category->thumbnail_url) . '" alt="' . esc_attr($category_label) . '" class="maca-category-thumbnail">';
            }
        echo '<span class="maca-category-name">' . esc_html($category_label) . '</span>';
        echo '</div>';
        echo '</button>';
        echo '</div>';
        $this->render_display_mode_containers();
    }
    
    /**
     * Render all categories with their active menus
     */
    private function render_all_categories_with_menus() {
        $categories = maca_menulist_db_get_categories(false);
        
        if (empty($categories)) {
            echo '<p>' . esc_html__('No menu categories available.', 'maca-restu-pro') . '</p>';
            return;
        }
        
        echo '<div class="maca-categories-list">';
        
        foreach ($categories as $category) {
            $menus = maca_menulist_get_published_menus_for_category($category->id);

            echo '<div class="maca-category-item">';
            echo '<h3 class="maca-category-title">' . esc_html(maca_menulist_get_category_display_name($category)) . '</h3>';

            if (empty($menus)) {
                echo '<p class="maca-no-menu">' . esc_html__('No active menu for this category.', 'maca-restu-pro') . '</p>';
            } else {
                foreach ($menus as $menu) {
                    $this->render_menu_content($menu, 'inline', array(
                        'schedule_note' => maca_menulist_get_website_schedule_note($menu),
                    ));
                }
            }

            echo '</div>';
        }
        
        echo '</div>';
    }
    
    /**
     * Render specific category's active menu
     */
    private function render_category_menu($category_id) {
        $menu = maca_menulist_get_menu_for_website($category_id);

        if (!$menu) {
            echo '<p>' . esc_html__('No active menu available for this category.', 'maca-restu-pro') . '</p>';
            return;
        }

        $this->render_menu_content($menu, 'inline', array(
            'schedule_note' => maca_menulist_get_website_schedule_note($menu),
        ));
    }
    
    /**
     * Render menu content (image or PDF)
     */
    private function render_menu_content($menu, $context = 'inline', $options = array()) {
        $is_standalone = ($context === 'standalone');
        $is_qr = ($context === 'qr');
        $container_class = 'maca-menu-container';
        if ($is_standalone) {
            $container_class .= ' maca-menu-container-standalone';
        }
        if ($is_qr) {
            $container_class .= ' maca-menu-container-qr';
        }

        $show_title = array_key_exists('show_title', $options)
            ? (bool) $options['show_title']
            : maca_menulist_show_menu_title();
        if ($is_qr) {
            $show_title = false;
        }
        $schedule_note = isset($options['schedule_note']) ? $options['schedule_note'] : '';
        $menu_title = maca_menulist_get_menu_display_title($menu);

        echo '<div class="' . esc_attr($container_class) . '">';
        if ($show_title) {
            echo '<h2 class="maca-menu-title">' . esc_html($menu_title) . '</h2>';
        }
        if ($schedule_note !== '') {
            echo '<p class="maca-menu-schedule-note">' . esc_html($schedule_note) . '</p>';
        }

        if ($menu->file_type === 'pdf') {
            $iframe_style = $is_standalone || $is_qr
                ? 'width:100%;height:90vh;min-height:500px;border:0;display:block;'
                : 'width:100%;height:90vh;min-height:500px;max-height:900px;border:0;display:block;';

            echo '<div class="maca-pdf-embed">';
            echo '<iframe src="' . esc_url($menu->file_url . '#toolbar=0&navpanes=0&scrollbar=1') . '" title="' . esc_attr($menu_title) . '" style="' . esc_attr($iframe_style) . '"></iframe>';
            echo '</div>';
            if (!$is_qr) {
                echo '<p class="maca-pdf-fallback"><a href="' . esc_url($menu->file_url) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('Open PDF in new tab if it does not display above', 'maca-restu-pro') . '</a></p>';
            }
        } else {
            echo '<div class="maca-menu-image">';
            echo '<img src="' . esc_url($menu->file_url) . '" alt="' . esc_attr($menu_title) . '">';
            echo '</div>';
        }

        echo '</div>';
    }

    /**
     * Close button for standalone menu viewer (new page / new tab).
     */
    private function render_menu_viewer_close_ui() {
        ?>
    <button type="button" class="maca-menu-close maca-menu-close--viewer" id="maca-viewer-close" aria-label="<?php echo esc_attr__('Close menu', 'maca-restu-pro'); ?>">&times;</button>
    <script>
        (function () {
            var homeUrl = <?php echo wp_json_encode(home_url('/')); ?>;

            function closeViewer() {
                if (window.opener && !window.opener.closed) {
                    window.close();
                    return;
                }

                try {
                    window.close();
                } catch (e) {
                    // Ignore – close() may be blocked by the browser.
                }

                if (window.history.length > 1) {
                    window.history.back();
                    return;
                }

                window.location.href = homeUrl;
            }

            var closeButton = document.getElementById('maca-viewer-close');
            if (closeButton) {
                closeButton.addEventListener('click', closeViewer);
            }
        })();
    </script>
        <?php
    }

    /**
     * Render a standalone HTML page for new-tab menu viewing.
     */
    private function render_menu_viewer_page($menu) {
        status_header(200);
        nocache_headers();

        $menu_title = maca_menulist_get_menu_display_title($menu);

        ?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo('charset'); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo esc_html($menu_title); ?></title>
    <?php // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet -- Standalone viewer exits before theme output. ?>
    <link rel="stylesheet" href="<?php echo esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/css/style.css?ver=' . MACA_MENULIST_VERSION); ?>">
    <style>
        body {
            margin: 0;
            background: #f5f5f5;
            font-family: Arial, sans-serif;
        }
        .maca-menu-viewer {
            max-width: 1200px;
            margin: 0 auto;
            padding: 0;
        }
        .maca-menu-container-standalone {
            margin: 0;
            padding: 0;
            box-shadow: none;
            border-radius: 0;
        }
        .maca-menu-container-standalone .maca-menu-title {
            margin: 0;
            padding: 12px 16px;
            font-size: 18px;
        }
        .maca-menu-container-standalone .maca-pdf-embed {
            margin: 0;
            border: none;
            border-radius: 0;
        }
        .maca-menu-container-standalone .maca-pdf-fallback {
            margin: 0;
            padding: 8px 16px 16px;
            font-size: 13px;
            text-align: center;
        }
        .maca-menu-container-standalone .maca-menu-image {
            padding: 16px;
        }
        .maca-pdf-js-view .maca-menu-title {
            text-align: center;
            padding: 12px 16px;
            margin: 0;
        }
        .maca-pdf-js-pages {
            padding: 0 8px 24px;
        }
    </style>
    <script>window.macaMenulistPdfConfig = <?php echo wp_json_encode(array(
        'pdfLibUrl' => MACA_MENULIST_PLUGIN_URL . 'assets/vendor/pdfjs/pdf.min.js',
        'workerUrl' => MACA_MENULIST_PLUGIN_URL . 'assets/vendor/pdfjs/pdf.worker.min.js',
        'showMenuTitle' => maca_menulist_show_menu_title(),
    )); ?>;</script>
    <?php // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Standalone viewer exits before theme output. ?>
    <script src="<?php echo esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/js/maca-pdf.js'); ?>"></script>
</head>
<body>
    <div class="maca-menu-viewer" id="maca-viewer-root">
        <?php
        if ($menu->file_type !== 'pdf') {
            $this->render_menu_content($menu, 'standalone', array(
                'show_title' => maca_menulist_show_menu_title(),
            ));
        }
        ?>
    </div>
    <?php if ($menu->file_type === 'pdf') : ?>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            if (!window.MacaMenulistPdf) {
                return;
            }
            MacaMenulistPdf.render(
                document.getElementById('maca-viewer-root'),
                <?php echo wp_json_encode($menu->file_url); ?>,
                <?php echo wp_json_encode($menu_title); ?>,
                {
                    loadingText: <?php echo wp_json_encode(__('Loading menu...', 'maca-restu-pro')); ?>,
                    showTitle: <?php echo maca_menulist_show_menu_title() ? 'true' : 'false'; ?>
                }
            );
        });
    </script>
    <?php endif; ?>
    <?php $this->render_menu_viewer_close_ui(); ?>
</body>
</html>
        <?php
        exit;
    }

    /**
     * Render a simple HTML error page for new-tab menu viewing.
     */
    private function render_menu_viewer_error($message, $status = 400) {
        status_header($status);
        nocache_headers();
        ?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo('charset'); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php esc_html_e('Menu', 'maca-restu-pro'); ?></title>
    <?php // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet -- Standalone error page exits before theme output. ?>
    <link rel="stylesheet" href="<?php echo esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/css/style.css?ver=' . MACA_MENULIST_VERSION); ?>">
    <style>
        body {
            margin: 0;
            padding: 40px 20px;
            font-family: Arial, sans-serif;
            text-align: center;
            background: #f5f5f5;
            color: #333;
        }
    </style>
</head>
<body>
    <p><?php echo esc_html($message); ?></p>
    <?php $this->render_menu_viewer_close_ui(); ?>
</body>
</html>
        <?php
        exit;
    }
    
    /**
     * Get category ID by name
     */
    private function get_category_id_by_name($category_name) {
        return maca_menulist_db_get_category_id_by_name($category_name);
    }
    
    /**
     * Get active menu for a category based on schedule
     */
    private function get_active_menu_for_category($category_id) {
        return maca_menulist_get_active_menu_for_category($category_id);
    }

    /**
     * Resolve menu for website shortcode (shows published menus outside live hours too).
     */
    private function get_menu_for_website($category_id) {
        return maca_menulist_get_menu_for_website($category_id);
    }
    
    /**
     * AJAX handler for loading category menu
     */
    /**
     * AJAX handler for guest dish ratings.
     */
    public function ajax_rate_dish() {
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';

        if (!wp_verify_nonce($nonce, 'maca_dish_rating_nonce')) {
            wp_send_json_error(array('message' => __('Invalid request.', 'maca-restu-pro')));
        }

        if (!maca_menulist_dish_guest_ratings_enabled()) {
            wp_send_json_error(array('message' => __('Ratings are not enabled.', 'maca-restu-pro')));
        }

        $dish_id = isset($_POST['dish_id']) ? intval($_POST['dish_id']) : 0;
        $rating = isset($_POST['rating']) ? intval($_POST['rating']) : 0;

        if ($dish_id <= 0 || $rating < 1 || $rating > 5) {
            wp_send_json_error(array('message' => __('Invalid rating.', 'maca-restu-pro')));
        }

        $dish = maca_menulist_db_get_dish($dish_id);
        if (!$dish || !(int) $dish->is_active) {
            wp_send_json_error(array('message' => __('Dish not found.', 'maca-restu-pro')));
        }

        $voter_key = maca_menulist_ensure_dish_rating_voter_key();
        if ($voter_key === '' || !maca_menulist_db_save_dish_rating($dish_id, $rating, $voter_key)) {
            wp_send_json_error(array('message' => __('Could not save rating.', 'maca-restu-pro')));
        }

        $summary = maca_menulist_db_get_dish_rating_summary($dish_id);

        wp_send_json_success(array(
            'average' => $summary['average'],
            'count' => $summary['count'],
            'user_rating' => $rating,
        ));
    }

    /**
     * AJAX handler for dish click / view tracking.
     */
    public function ajax_track_dish_view() {
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';

        if (!wp_verify_nonce($nonce, 'maca_dish_track_nonce')) {
            wp_send_json_error(array('message' => __('Invalid request.', 'maca-restu-pro')));
        }

        if (!maca_menulist_is_public_dishes_mode()) {
            wp_send_json_error(array('message' => __('Not available.', 'maca-restu-pro')));
        }

        $dish_id = isset($_POST['dish_id']) ? absint(wp_unslash($_POST['dish_id'])) : 0;
        $event_type = isset($_POST['event_type']) ? sanitize_key(wp_unslash($_POST['event_type'])) : 'click_card';

        if ($dish_id <= 0) {
            wp_send_json_error(array('message' => __('Invalid dish.', 'maca-restu-pro')));
        }

        $viewer_key = '';
        if (function_exists('maca_menulist_ensure_dish_rating_voter_key')) {
            $viewer_key = maca_menulist_ensure_dish_rating_voter_key();
        }

        if (!function_exists('maca_menulist_db_record_dish_view')) {
            require_once MACA_MENULIST_PLUGIN_DIR . 'includes/db-dish-stats.php';
        }
        maca_menulist_db_record_dish_view($dish_id, $event_type, $viewer_key);

        wp_send_json_success(array('recorded' => true));
    }

    /**
     * AJAX handler for guest table order submission.
     */
    public function ajax_submit_table_order() {
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';

        if (!wp_verify_nonce($nonce, 'maca_table_order_nonce')) {
            wp_send_json_error(array('message' => __('Invalid request.', 'maca-restu-pro')));
        }

        if (!maca_menulist_table_order_enabled() || !maca_menulist_table_order_uses_server()) {
            wp_send_json_error(array('message' => __('Server orders are not enabled.', 'maca-restu-pro')));
        }

        $order_channel = isset($_POST['order_channel']) ? sanitize_key(wp_unslash($_POST['order_channel'])) : 'dine_in';
        if (!in_array($order_channel, array('dine_in', 'takeaway'), true)) {
            $order_channel = 'dine_in';
        }

        $table_number = isset($_POST['table_number']) ? sanitize_text_field(wp_unslash($_POST['table_number'])) : '';
        $prefill_table = isset($_POST['url_table']) ? sanitize_text_field(wp_unslash($_POST['url_table'])) : '';
        $pickup_name = isset($_POST['pickup_name']) ? sanitize_text_field(wp_unslash($_POST['pickup_name'])) : '';
        $pickup_phone = isset($_POST['pickup_phone']) ? sanitize_text_field(wp_unslash($_POST['pickup_phone'])) : '';

        if ($order_channel === 'takeaway') {
            if (!maca_menulist_takeaway_guest_ordering_allowed()) {
                wp_send_json_error(
                    array(
                        'message' => __(
                            'Takeaway ordering requires guest payments to be enabled (prices, Stripe or pay at table).',
                            'maca-restu-pro'
                        ),
                    )
                );
            }

            if (
                function_exists('maca_menulist_takeaway_accepting_orders_now')
                && !maca_menulist_takeaway_accepting_orders_now()
            ) {
                wp_send_json_error(
                    array(
                        'message' => function_exists('maca_menulist_get_takeaway_outside_hours_notice')
                            ? maca_menulist_get_takeaway_outside_hours_notice()
                            : __('Takeaway is closed right now.', 'maca-restu-pro'),
                    )
                );
            }

            $table_number = '';
        } elseif (
            $table_number !== ''
            && function_exists('maca_menulist_is_allowed_guest_order_table_number')
            && !maca_menulist_is_allowed_guest_order_table_number($table_number, $prefill_table)
        ) {
            wp_send_json_error(array('message' => __('Invalid table number.', 'maca-restu-pro')));
        }

        $order_note = isset($_POST['order_note']) ? sanitize_textarea_field(wp_unslash($_POST['order_note'])) : '';
        $items_raw = isset($_POST['items']) ? wp_unslash($_POST['items']) : '';

        if (is_string($items_raw)) {
            $items = json_decode($items_raw, true);
        } else {
            $items = $items_raw;
        }

        if (!is_array($items) || empty($items)) {
            wp_send_json_error(array('message' => __('Order is empty.', 'maca-restu-pro')));
        }

        $lines = array();
        $apply_qr_schedule = isset($_POST['qr_schedule']) && sanitize_text_field(wp_unslash($_POST['qr_schedule'])) === '1';
        $is_takeaway_order = ($order_channel === 'takeaway');

        foreach ($items as $item) {
            if (!is_array($item)) {
                continue;
            }

            $dish_id = isset($item['id']) ? intval($item['id']) : 0;
            $line_price = null;
            if ($dish_id > 0) {
                $dish = maca_menulist_db_get_dish($dish_id);
                if ($is_takeaway_order) {
                    if (!$dish || !maca_menulist_dish_is_available_for_takeaway($dish)) {
                        continue;
                    }
                    $line_price = maca_menulist_get_dish_price_raw($dish, 'takeaway');
                } else {
                    if (!$dish || !maca_menulist_dish_is_visible_on_website($dish)) {
                        continue;
                    }
                    if ($apply_qr_schedule && !maca_menulist_dish_is_visible_on_qr($dish)) {
                        continue;
                    }
                    $line_price = maca_menulist_get_dish_price_raw($dish, 'dine_in');
                }
            }

            $title = isset($item['title']) ? sanitize_text_field($item['title']) : '';
            if ($title === '') {
                continue;
            }

            if ($line_price === null && isset($item['price']) && $item['price'] !== '' && $item['price'] !== null) {
                $line_price = (float) $item['price'];
            }

            $lines[] = array(
                'id' => isset($item['id']) ? intval($item['id']) : 0,
                'title' => $title,
                'qty' => isset($item['qty']) ? max(1, (int) $item['qty']) : 1,
                'note' => isset($item['note']) ? sanitize_text_field($item['note']) : '',
                'price' => $line_price,
            );
        }

        if (empty($lines)) {
            wp_send_json_error(array('message' => __('Order is empty.', 'maca-restu-pro')));
        }

        $guest_token = isset($_POST['guest_token']) ? sanitize_text_field(wp_unslash($_POST['guest_token'])) : '';

        if ($guest_token !== '') {
            $existing_order = maca_menulist_db_get_table_order_by_token($guest_token);

            if ($existing_order) {
                $existing_table = trim((string) $existing_order->table_number);

                if (
                    $table_number !== ''
                    && $existing_table !== ''
                    && $table_number !== $existing_table
                ) {
                    wp_send_json_error(array('message' => __('Table number cannot be changed for an existing order.', 'maca-restu-pro')));
                }

                if ($existing_table !== '') {
                    $table_number = $existing_table;
                }
            }

            if (
                $existing_order
                && maca_menulist_table_order_allows_append((string) $existing_order->status, $existing_order)
                && maca_menulist_db_append_table_order_lines((int) $existing_order->id, $lines, $order_note)
            ) {
                $appended_order = maca_menulist_db_get_table_order((int) $existing_order->id);
                if ($appended_order) {
                    $appended_rows = maca_menulist_db_attach_table_order_lines(array($appended_order));
                    $appended_order = !empty($appended_rows[0]) ? $appended_rows[0] : $appended_order;
                }

                $append_message = __('Items added to your order!', 'maca-restu-pro');
                $requires_additional_payment = false;

                if (
                    $appended_order
                    && function_exists('maca_menulist_get_order_payment_balance')
                ) {
                    $balance = maca_menulist_get_order_payment_balance($appended_order);
                    if ($balance['remaining'] > 0.009) {
                        $requires_additional_payment = true;
                        $append_message = __(
                            'Items added. Please pay the remaining balance to confirm your add-on order.',
                            'maca-restu-pro'
                        );
                    }
                }

                $response = array(
                    'order_id' => (int) $existing_order->id,
                    'guest_token' => $guest_token,
                    'appended' => true,
                    'requires_additional_payment' => $requires_additional_payment,
                    'message' => $append_message,
                );

                if (maca_menulist_table_order_guest_status_enabled() || $requires_additional_payment) {
                    $response['guest_status'] = true;
                }

                wp_send_json_success($response);
            }
        }

        $service_mode = $is_takeaway_order ? 'takeaway' : 'dine_in';

        $inserted = maca_menulist_db_insert_table_order(
            array(
                'table_number' => $table_number,
                'service_mode' => $service_mode,
                'pickup_name' => $pickup_name,
                'pickup_phone' => $pickup_phone,
                'order_note' => $order_note,
            ),
            $lines
        );

        if (!is_array($inserted) || empty($inserted['id'])) {
            wp_send_json_error(array('message' => __('Could not save order.', 'maca-restu-pro')));
        }

        $order_rows = maca_menulist_db_attach_table_order_lines(
            array(maca_menulist_db_get_table_order((int) $inserted['id']))
        );
        $saved_order = !empty($order_rows[0]) ? $order_rows[0] : null;

        $requires_prepayment = $saved_order
            && function_exists('maca_menulist_order_requires_takeaway_prepayment')
            && maca_menulist_order_requires_takeaway_prepayment($saved_order);

        $response = array(
            'order_id' => (int) $inserted['id'],
            'appended' => false,
            'requires_prepayment' => $requires_prepayment,
            'message' => $requires_prepayment
                ? __('Complete payment — the kitchen will start preparing your order after payment.', 'maca-restu-pro')
                : __('Order sent! The staff has been notified.', 'maca-restu-pro'),
        );

        if (maca_menulist_table_order_guest_status_enabled() || $requires_prepayment) {
            $response['guest_token'] = $inserted['guest_token'];
            $response['guest_status'] = true;
        } elseif (maca_menulist_table_order_uses_server()) {
            $response['guest_token'] = $inserted['guest_token'];
        }

        wp_send_json_success($response);
    }

    /**
     * AJAX handler for guest order status polling.
     */
    public function ajax_get_guest_order_status() {
        $guest_token = isset($_POST['guest_token']) ? sanitize_text_field(wp_unslash($_POST['guest_token'])) : '';

        if ($guest_token === '' || !maca_menulist_table_order_guest_status_enabled()) {
            wp_send_json_error(array('message' => __('Invalid request.', 'maca-restu-pro')));
        }

        $order = maca_menulist_db_get_table_order_by_token($guest_token);

        if (!$order) {
            wp_send_json_error(array('message' => __('Order not found.', 'maca-restu-pro')));
        }

        $orders = maca_menulist_db_attach_table_order_lines(array($order));

        wp_send_json_success(maca_menulist_format_guest_order_status_for_json($orders[0]));
    }

    /**
     * AJAX handler for kitchen/waiter status updates.
     */
    public function ajax_update_staff_order_status() {
        if (function_exists('maca_menulist_mark_staff_api_request')) {
            maca_menulist_mark_staff_api_request();
        }

        $pin = maca_menulist_assert_staff_pin_or_json_error();
        $order_id = isset($_POST['order_id']) ? intval($_POST['order_id']) : 0;
        $status = isset($_POST['status']) ? sanitize_key(wp_unslash($_POST['status'])) : '';
        $view = isset($_POST['view']) ? sanitize_key(wp_unslash($_POST['view'])) : 'kitchen';
        $eta_minutes = isset($_POST['eta_minutes']) ? intval($_POST['eta_minutes']) : null;

        if ($order_id <= 0 || !maca_menulist_is_valid_table_order_status($status)) {
            wp_send_json_error(array('message' => __('Could not update order.', 'maca-restu-pro')));
        }

        $order_row = maca_menulist_db_get_table_order($order_id);

        if (!$order_row) {
            wp_send_json_error(array('message' => __('Order not found.', 'maca-restu-pro')));
        }

        if ($view === 'kitchen') {
            $validation = maca_menulist_validate_kitchen_status_change(
                (string) $order_row->status,
                $status,
                $eta_minutes
            );

            if (!$validation['allowed']) {
                wp_send_json_error(
                    array(
                        'message' => isset($validation['message'])
                            ? $validation['message']
                            : __('Invalid status change.', 'maca-restu-pro'),
                    )
                );
            }

            $status = $validation['status'];
            $eta_minutes = $validation['eta_minutes'];
            $eta_only = !empty($validation['eta_only']);
        } else {
            $eta_only = false;
            if ($status !== 'ready') {
                $eta_minutes = null;
            }
        }

        $order_with_lines = maca_menulist_db_attach_table_order_lines(array($order_row))[0];

        if ($view === 'waiter') {
            $allowed = maca_menulist_get_waiter_order_actions_for_order($order_with_lines);
            $allowed_statuses = array_map(
                static function ($action) {
                    return $action['status'];
                },
                $allowed
            );

            if (!in_array($status, $allowed_statuses, true)) {
                wp_send_json_error(array('message' => __('Invalid status change.', 'maca-restu-pro')));
            }
        }

        if (
            $view === 'kitchen'
            && function_exists('maca_menulist_order_blocks_kitchen_until_prepayment')
            && maca_menulist_order_blocks_kitchen_until_prepayment($order_with_lines)
        ) {
            wp_send_json_error(
                array(
                    'message' => __(
                        'Payment must be completed before the kitchen can accept this takeaway order.',
                        'maca-restu-pro'
                    ),
                )
            );
        }

        $register_partial_payment = $status === 'paid'
            && $view === 'waiter'
            && !maca_menulist_order_is_payment_complete($order_with_lines);

        $register_split_share = $register_partial_payment
            && maca_menulist_order_bill_split_is_active($order_with_lines);

        if ($register_partial_payment && function_exists('maca_menulist_db_apply_order_payment')) {
            maca_menulist_db_apply_order_payment(
                $order_id,
                array(
                    'payment_provider' => 'manual',
                    'payment_method' => !empty($order_row->payment_method) ? (string) $order_row->payment_method : 'manual',
                )
            );

            $fresh = maca_menulist_db_get_table_order($order_id);
            $response_status = 'served';
            $keep_kitchen_status_new = function_exists('maca_menulist_order_requires_takeaway_prepayment')
                && maca_menulist_order_requires_takeaway_prepayment($order_with_lines)
                && maca_menulist_normalize_table_order_status((string) $order_row->status) === 'new';

            if ($fresh && maca_menulist_order_is_payment_complete($fresh)) {
                if ($keep_kitchen_status_new) {
                    $response_status = 'new';
                } else {
                    maca_menulist_db_update_table_order_status($order_id, 'paid', null);
                    $response_status = 'paid';
                }
            }

            wp_send_json_success(array(
                'order_id' => $order_id,
                'status' => maca_menulist_normalize_table_order_status($response_status),
            ));
        }

        if ($view === 'kitchen' && !empty($eta_only)) {
            if (!maca_menulist_db_set_table_order_eta($order_id, (int) $eta_minutes)) {
                wp_send_json_error(array('message' => __('Could not update order.', 'maca-restu-pro')));
            }
        } elseif (!maca_menulist_db_update_table_order_status($order_id, $status, $eta_minutes)) {
            wp_send_json_error(array('message' => __('Could not update order.', 'maca-restu-pro')));
        }

        if (
            $status === 'paid'
            && function_exists('maca_menulist_db_apply_order_payment')
            && !$register_partial_payment
        ) {
            $fresh = maca_menulist_db_get_table_order($order_id);
            if ($fresh && !maca_menulist_order_is_payment_complete($fresh)) {
                $fresh_with_lines = maca_menulist_db_attach_table_order_lines(array($fresh))[0];
                maca_menulist_db_apply_order_payment(
                    $order_id,
                    array(
                        'payment_provider' => 'manual',
                        'payment_method' => !empty($fresh->payment_method) ? (string) $fresh->payment_method : 'manual',
                        'payment_amount' => maca_menulist_order_payment_total($fresh_with_lines),
                    )
                );
            }
        }

        wp_send_json_success(array(
            'order_id' => $order_id,
            'status' => maca_menulist_normalize_table_order_status($status),
        ));
    }

    /**
     * AJAX handler for staff table number updates.
     */
    public function ajax_update_staff_order_table() {
        $result = maca_menulist_staff_api_dispatch('maca_update_staff_order_table');
        if (empty($result['success'])) {
            wp_send_json_error($result['data'], $result['status'] ?? 403);
        }

        wp_send_json_success($result['data']);
    }

    /**
     * AJAX handler for staff order polling.
     */
    public function ajax_get_staff_orders() {
        if (function_exists('maca_menulist_mark_staff_api_request')) {
            maca_menulist_mark_staff_api_request();
        }

        $result = maca_menulist_staff_api_dispatch('maca_get_staff_orders');
        if (empty($result['success'])) {
            wp_send_json_error($result['data'], $result['status'] ?? 403);
        }

        wp_send_json_success($result['data']);
    }

    /**
     * AJAX handler for marking an order as handled.
     */
    public function ajax_handle_staff_order() {
        $result = maca_menulist_staff_api_dispatch('maca_handle_staff_order');
        if (empty($result['success'])) {
            wp_send_json_error($result['data'], $result['status'] ?? 403);
        }

        wp_send_json_success($result['data']);
    }

    /**
     * Handle staff board POST requests on the public staff page (same-origin fallback).
     *
     * @return void
     */
    public function maybe_handle_staff_orders_post() {
        static $handled = false;

        if ($handled) {
            return;
        }

        if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
            return;
        }

        if (defined('DOING_AJAX') && DOING_AJAX) {
            return;
        }

        if (!maca_menulist_is_staff_orders_request()) {
            if (!function_exists('maca_menulist_bootstrap_staff_request_query_vars')
                || !maca_menulist_bootstrap_staff_request_query_vars()) {
                return;
            }
        }

        $action = function_exists('maca_menulist_get_staff_action_from_request')
            ? maca_menulist_get_staff_action_from_request()
            : '';
        if ($action === '') {
            return;
        }

        if (!in_array($action, maca_menulist_get_staff_api_actions(), true)) {
            return;
        }

        if (function_exists('maca_menulist_mark_staff_api_request')) {
            maca_menulist_mark_staff_api_request();
        }

        if ($action === 'maca_update_staff_order_status') {
            $handled = true;
            $this->ajax_update_staff_order_status();
            return;
        }

        $handled = true;
        $result = maca_menulist_staff_api_dispatch($action);
        if (empty($result['success'])) {
            wp_send_json_error($result['data'], $result['status'] ?? 403);
        }

        wp_send_json_success($result['data']);
    }

    /**
     * Render staff order page (waiter or kitchen).
     */
    public function handle_staff_orders_page() {
        if (!maca_menulist_is_staff_orders_request()) {
            return;
        }

        if (function_exists('maca_menulist_mark_staff_api_request')) {
            maca_menulist_mark_staff_api_request();
        }

        if (function_exists('maca_menulist_legal_blocks_frontend') && maca_menulist_legal_blocks_frontend()) {
            maca_menulist_legal_render_blocked_page();
        }

        $block_reason = maca_menulist_get_staff_order_pages_block_reason();
        if ($block_reason !== '') {
            status_header(200);
            wp_die(
                esc_html($block_reason),
                esc_html__('Staff order page unavailable', 'maca-restu-pro'),
                array('response' => 200)
            );
        }

        $view = maca_menulist_get_staff_orders_view();

        if ($view === 'kitchen' && !maca_menulist_table_order_kitchen_page_enabled()) {
            wp_die(esc_html__('Kitchen order page is not enabled.', 'maca-restu-pro'));
        }

        if ($view === 'waiter' && !maca_menulist_table_order_waiter_page_enabled()) {
            wp_die(esc_html__('Waiter order page is not enabled.', 'maca-restu-pro'));
        }

        if (maca_menulist_get_table_order_staff_pin() === '') {
            wp_die(esc_html__('Staff PIN is not configured. Set it in maca Restu settings.', 'maca-restu-pro'));
        }
        $pin_feedback = maca_menulist_get_staff_pin_attempt_feedback();

        status_header(200);
        nocache_headers();

        $title = $view === 'kitchen'
            ? __('Kitchen orders', 'maca-restu-pro')
            : __('Waiter orders', 'maca-restu-pro');

        $kitchen_kds = $view === 'kitchen';
        $stylesheets = array(
            MACA_MENULIST_PLUGIN_URL . 'assets/css/style.css?ver=' . MACA_MENULIST_VERSION,
        );
        if ($kitchen_kds) {
            $stylesheets[] = MACA_MENULIST_PLUGIN_URL . 'assets/css/staff-kitchen-kds.css?ver=' . MACA_MENULIST_VERSION;
        }

        // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Security.EscapeOutput.OutputNotEscaped
        echo '<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <title>' . esc_html($title) . '</title>';
        foreach ($stylesheets as $stylesheet) {
            echo '<link rel="stylesheet" href="' . esc_url($stylesheet) . '">';
        }
        echo '
</head>
<body class="maca-staff-orders-page maca-staff-orders-page--' . esc_attr($view) . ($kitchen_kds ? ' maca-staff-orders-page--kds' : '') . '">
    <div id="maca-staff-orders-app" class="maca-staff-orders-app" data-view="' . esc_attr($view) . '">
        <div id="maca-staff-orders-pin" class="maca-staff-orders-pin">
            <h1>' . esc_html($title) . '</h1>
            <label for="maca-staff-orders-pin-input">' . esc_html__('Enter staff PIN', 'maca-restu-pro') . '</label>
            <input type="password" id="maca-staff-orders-pin-input" class="maca-staff-orders-pin-input" inputmode="numeric" autocomplete="off" placeholder="' . esc_attr__('PIN', 'maca-restu-pro') . '">
            <p id="maca-staff-orders-pin-info" class="maca-staff-orders-pin-info">' . esc_html(
                $pin_feedback['is_locked']
                    ? sprintf(
                        /* translators: %d: lockout minutes remaining */
                        __('PIN locked. Try again in %d min.', 'maca-restu-pro'),
                        max(1, (int) ceil($pin_feedback['locked_seconds_remaining'] / 60))
                    )
                    : sprintf(
                        /* translators: 1: attempts left, 2: max attempts */
                        __('Attempts left: %1$d of %2$d', 'maca-restu-pro'),
                        (int) $pin_feedback['attempts_left'],
                        (int) $pin_feedback['max_attempts']
                    )
            ) . '</p>
            <button type="button" id="maca-staff-orders-unlock" class="maca-staff-orders-unlock">' . esc_html__('Show orders', 'maca-restu-pro') . '</button>
            <p id="maca-staff-orders-pin-error" class="maca-staff-orders-pin-error" hidden></p>
        </div>';

        if ($kitchen_kds) {
            echo '
        <div id="maca-staff-orders-board" class="maca-staff-orders-board maca-kds-board" hidden>
            <div class="maca-kds-layout">
                <div class="maca-kds-main">
                    <header class="maca-kds-topbar">
                        <h1 class="maca-kds-title">' . esc_html($title) . '</h1>
                    </header>
                    <div class="maca-kds-columns">
                        <section class="maca-kds-column maca-kds-column--new" data-column="new" aria-label="' . esc_attr__('New orders', 'maca-restu-pro') . '">
                            <header class="maca-kds-column-header">
                                <h2>' . esc_html__('New orders', 'maca-restu-pro') . '</h2>
                                <span class="maca-kds-column-count" data-count-for="new">0</span>
                            </header>
                            <div class="maca-kds-column-body" data-column-body="new"></div>
                        </section>
                        <section class="maca-kds-column maca-kds-column--progress" data-column="progress" aria-label="' . esc_attr__('In progress', 'maca-restu-pro') . '">
                            <header class="maca-kds-column-header">
                                <h2>' . esc_html__('In progress', 'maca-restu-pro') . '</h2>
                                <span class="maca-kds-column-count" data-count-for="progress">0</span>
                            </header>
                            <div class="maca-kds-column-body" data-column-body="progress"></div>
                        </section>
                        <section class="maca-kds-column maca-kds-column--ready" data-column="ready" aria-label="' . esc_attr__('Ready', 'maca-restu-pro') . '">
                            <header class="maca-kds-column-header">
                                <h2>' . esc_html__('Ready', 'maca-restu-pro') . '</h2>
                                <span class="maca-kds-column-count" data-count-for="ready">0</span>
                            </header>
                            <div class="maca-kds-column-body" data-column-body="ready"></div>
                        </section>
                    </div>
                    <p id="maca-staff-orders-empty" class="maca-kds-empty" hidden>' . esc_html__('No active orders right now.', 'maca-restu-pro') . '</p>
                </div>
                <aside class="maca-kds-stats" aria-label="' . esc_attr__('Kitchen stats', 'maca-restu-pro') . '">
                    <div class="maca-kds-stat">
                        <span class="maca-kds-stat-label">' . esc_html__('Kitchen time', 'maca-restu-pro') . '</span>
                        <span class="maca-kds-stat-value" id="maca-kds-clock">--:--</span>
                    </div>
                    <div class="maca-kds-stat">
                        <span class="maca-kds-stat-label">' . esc_html__('Average time', 'maca-restu-pro') . '</span>
                        <span class="maca-kds-stat-value" id="maca-kds-avg-time">—</span>
                    </div>
                    <div class="maca-kds-stat">
                        <span class="maca-kds-stat-label">' . esc_html__('Orders today', 'maca-restu-pro') . '</span>
                        <span class="maca-kds-stat-value" id="maca-kds-orders-today">0</span>
                    </div>
                </aside>
            </div>
        </div>';
        } else {
            echo '
        <div id="maca-staff-orders-board" class="maca-staff-orders-board" hidden>
            <div class="maca-staff-orders-board-header">
                <h1 id="maca-staff-orders-heading" class="maca-staff-orders-heading">' . esc_html($title) . '</h1>
                <div id="maca-staff-waiter-filter" class="maca-staff-waiter-filter" hidden>
                    <label for="maca-staff-waiter-filter-select" class="maca-staff-waiter-filter-label">' . esc_html__('Show orders for', 'maca-restu-pro') . '</label>
                    <select id="maca-staff-waiter-filter-select" class="maca-staff-waiter-filter-select"></select>
                </div>
                <p id="maca-staff-orders-status" class="maca-staff-orders-status"></p>
            </div>
            <div id="maca-staff-table-board" class="maca-staff-table-board">
                <p class="maca-staff-table-board-hint">' . esc_html__('Tap a table to view and manage its orders.', 'maca-restu-pro') . '</p>
                <div id="maca-staff-table-grid" class="maca-staff-table-grid" role="list"></div>
                <p id="maca-staff-table-empty" class="maca-staff-table-empty" hidden>' . esc_html__('No active orders right now.', 'maca-restu-pro') . '</p>
            </div>
            <div id="maca-staff-table-detail" class="maca-staff-table-detail" hidden>
                <button type="button" id="maca-staff-table-back" class="maca-staff-table-back">' . esc_html__('All tables', 'maca-restu-pro') . '</button>
                <h2 id="maca-staff-table-detail-title" class="maca-staff-table-detail-title"></h2>
                <p id="maca-staff-table-detail-status" class="maca-staff-table-detail-status" hidden></p>
                <div id="maca-staff-orders-list" class="maca-staff-orders-list"></div>
                <p id="maca-staff-orders-empty" class="maca-staff-orders-empty" hidden>' . esc_html__('No orders for this table.', 'maca-restu-pro') . '</p>
            </div>
        </div>';
        }

        echo maca_menulist_render_staff_guest_qr_modal();
        echo '
    </div>
    <script>window.macaMenulistStaffOrders = ' . wp_json_encode(maca_menulist_get_staff_order_script_config($view)) . ';window.ajaxurl=window.ajaxurl||' . wp_json_encode(admin_url('admin-ajax.php')) . ';</script>
    <script src="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/js/staff-orders.js?ver=' . MACA_MENULIST_VERSION) . '"></script>
</body>
</html>';
        // phpcs:enable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Security.EscapeOutput.OutputNotEscaped

        exit;
    }

    public function ajax_load_category_menu() {
        $render_html = isset($_REQUEST['render_html']);
        $nonce = isset($_REQUEST['nonce']) ? sanitize_text_field(wp_unslash($_REQUEST['nonce'])) : '';

        if ($render_html) {
            if (empty($nonce) || !wp_verify_nonce($nonce, 'maca_menu_nonce')) {
                $this->render_menu_viewer_error(__('Invalid or expired link.', 'maca-restu-pro'), 403);
            }
        } elseif (!wp_verify_nonce($nonce, 'maca_menu_nonce')) {
            wp_send_json_error(array('message' => 'Invalid nonce'));
        }
        
        $category_id = isset($_REQUEST['category_id']) ? intval($_REQUEST['category_id']) : 0;
        $get_file_url = isset($_REQUEST['get_file_url']);
        
        if ($category_id <= 0) {
            if ($render_html) {
                $this->render_menu_viewer_error(__('Invalid category.', 'maca-restu-pro'), 400);
            }
            wp_send_json_error(array('message' => 'Invalid category ID'));
        }
        
        $strict_schedule = !empty($_REQUEST['qr_page']);
        $active_menu = $strict_schedule
            ? maca_menulist_get_active_menu_for_category($category_id)
            : maca_menulist_get_menu_for_website($category_id);

        if (!$active_menu) {
            if ($render_html) {
                $this->render_menu_viewer_error(__('No active menu available for this category.', 'maca-restu-pro'), 404);
            }
            wp_send_json_error();
        }

        if ($get_file_url) {
            wp_send_json_success(array('file_url' => $active_menu->file_url));
        }

        if ($render_html) {
            $this->render_menu_viewer_page($active_menu);
        }

        $context = $strict_schedule ? 'qr' : 'inline';
        $render_options = array();
        if (!$strict_schedule) {
            $render_options['schedule_note'] = maca_menulist_get_website_schedule_note($active_menu);
        }

        ob_start();
        $this->render_menu_content($active_menu, $context, $render_options);
        $html = ob_get_clean();

        wp_send_json_success(array(
            'html' => $html,
            'file_url' => $active_menu->file_url,
            'file_type' => $active_menu->file_type,
            'title' => maca_menulist_get_menu_display_title($active_menu),
            'schedule_note' => isset($render_options['schedule_note']) ? $render_options['schedule_note'] : '',
        ));
    }
    
    /**
     * Handle QR menu page
     */
    public function handle_qr_menu_page() {
        if (!maca_menulist_is_qr_menu_request()) {
            return;
        }

        if (function_exists('maca_menulist_legal_blocks_frontend') && maca_menulist_legal_blocks_frontend()) {
            maca_menulist_legal_render_blocked_page();
        }

        maca_menulist_load_textdomain();

        status_header(200);
        nocache_headers();

        if (maca_menulist_is_public_dishes_mode()) {
            $this->render_qr_dishes_page();
            return;
        }

        $url_category_id = maca_menulist_get_qr_url_category_id();
        $qr_category = $url_category_id > 0 ? $url_category_id : get_option('maca_menulist_qr_category', '');
        $qr_page_title = maca_menulist_get_qr_menu_page_title();
        $qr_display_mode = get_option('maca_menulist_qr_display_mode', 'full_page');
        $website_display_mode = get_option('maca_menulist_display_mode', 'inline');
        if (!in_array($website_display_mode, array('inline', 'popup', 'new_page'), true)) {
            $website_display_mode = 'inline';
        }

        // Get categories to display
        $categories_to_show = array();
        if (!empty($qr_category)) {
            $category = maca_menulist_db_get_category($qr_category);
            if ($category) {
                $categories_to_show[] = $category;
            }
        } else {
            $categories_to_show = maca_menulist_db_get_categories(true);
        }

        $categories_to_show = maca_menulist_filter_categories_with_active_menus($categories_to_show);

        // CSS for inline menu panel (website display mode must be inline)
        $menu_content_css = '';
        if ($website_display_mode === 'inline' && $qr_display_mode === 'full_page') {
            $menu_content_css = '
        .menu-content {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: #fff;
            z-index: 1000;
            overflow-y: auto;
        }';
        } elseif ($website_display_mode === 'inline') {
            $menu_content_css = '
        .menu-content {
            display: none;
            margin-top: 30px;
            padding: 20px;
            background: #f9f9f9;
            border-radius: 5px;
        }';
        }

        $close_button_css = '';
        if ($website_display_mode === 'inline' && $qr_display_mode === 'full_page') {
            $close_button_css = '
        .close-button {
            position: fixed;
            top: 20px;
            right: 20px;
            background: #0073aa;
            color: white;
            border: none;
            border-radius: 50%;
            width: 50px;
            height: 50px;
            font-size: 24px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 1001;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
        }';
        } elseif ($website_display_mode === 'inline') {
            $close_button_css = '
        .close-button {
            position: absolute;
            top: 10px;
            right: 10px;
            background: #0073aa;
            color: white;
            border: none;
            border-radius: 50%;
            width: 35px;
            height: 35px;
            font-size: 20px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
        }';
        }

        if ($website_display_mode === 'popup') {
            $menu_content_css .= '
        .maca-menu-popup {
            position: fixed;
        }
        .maca-menu-popup.active {
            display: block;
            opacity: 1;
            transform: translate(-50%, -50%) scale(1);
        }
        .maca-popup-overlay.active {
            display: block;
            opacity: 1;
        }';
        }

        // Standalone QR page exits before theme output; assets cannot use wp_enqueue_*.
        // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Security.EscapeOutput.OutputNotEscaped
        echo '<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>' . esc_html($qr_page_title) . '</title>
    <link rel="stylesheet" href="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/css/style.css?ver=' . MACA_MENULIST_VERSION) . '">
    <script>window.macaMenulistPdfConfig = ' . wp_json_encode(array(
        'pdfLibUrl' => MACA_MENULIST_PLUGIN_URL . 'assets/vendor/pdfjs/pdf.min.js',
        'workerUrl' => MACA_MENULIST_PLUGIN_URL . 'assets/vendor/pdfjs/pdf.worker.min.js',
        'showMenuTitle' => false,
    )) . ';</script>
    <script src="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/js/maca-pdf.js') . '"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: Arial, sans-serif;
            background: #f5f5f5;
            padding: 20px;
        }
        .menu-container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        .menu-title {
            text-align: center;
            font-size: 28px;
            font-weight: bold;
            margin-bottom: 30px;
            color: #333;
        }
        .category-buttons {
            margin-bottom: 16px;
        }
        .category-button {
            flex: 0 0 auto;
        }
        .menu-content.active {
            display: block;
        }
        .close-button:hover {
            background: #005177;
        }
        #menu-content .maca-menu-container {
            margin: 0;
            padding: 16px;
            max-width: 1200px;
            margin-left: auto;
            margin-right: auto;
            box-shadow: none;
        }
        #menu-content .maca-menu-title {
            text-align: center;
            margin-bottom: 16px;
        }
        #menu-content .maca-pdf-embed {
            margin: 0;
            border: none;
        }
        #menu-content .maca-pdf-embed iframe {
            width: 100%;
            height: 90vh;
            min-height: 500px;
            border: none;
            display: block;
        }
        #menu-content .maca-menu-image img {
            max-width: 100%;
            height: auto;
            display: block;
            margin: 0 auto;
        }
        #menu-content .maca-pdf-fallback {
            display: none;
        }
        .maca-qr-pdf-view {
            padding: 8px 0 24px;
        }
        .maca-qr-pdf-view .maca-menu-title {
            text-align: center;
            margin: 0 0 12px;
            font-size: 20px;
        }
        #maca-qr-pdf-pages {
            width: 100%;
            overflow-x: hidden;
        }
        .menu-image {
            max-width: 100%;
            height: auto;
            display: block;
            margin: 0 auto;
        }
        @media (max-width: 600px) {
            .menu-container {
                padding: 15px;
            }
            .close-button {
                top: 10px;
                right: 10px;
                width: 40px;
                height: 40px;
                font-size: 20px;
            }
        }
        ' . $menu_content_css . $close_button_css . '
    </style>
</head>
<body>
    <div class="menu-container">';
            maca_menulist_render_qr_menu_logo();
            echo '<h1 class="menu-title">' . esc_html($qr_page_title) . '</h1>';
            maca_menulist_render_menu_language_switcher(array('context' => 'qr'));

            if (empty($categories_to_show)) {
                echo '<p style="text-align:center;color:#666;padding:20px 0;">' . esc_html__('No menu is available right now. Please check back later.', 'maca-restu-pro') . '</p>';
            }

            echo '<div class="category-buttons maca-filter-bar">';
            
            foreach ($categories_to_show as $cat) {
                maca_menulist_normalize_category($cat);
                $category_label = maca_menulist_get_category_display_name($cat);
                echo '<button type="button" class="category-button" data-category-id="' . esc_attr($cat->id) . '">';
                if (!empty($cat->thumbnail_url)) {
                    echo '<img src="' . esc_url($cat->thumbnail_url) . '" alt="' . esc_attr($category_label) . '">';
                }
                echo '<span>' . esc_html($category_label) . '</span>';
                echo '</button>';
            }

            echo '</div>';

            echo '</div>';

            if ($website_display_mode === 'inline') {
                echo '<div id="menu-content" class="menu-content"></div>';
                echo '<button type="button" id="close-button" class="close-button" style="display: none;">&times;</button>';
            } elseif ($website_display_mode === 'popup') {
                echo '<div class="maca-menu-popup" id="maca-menu-popup">';
                echo '<button type="button" id="maca-qr-popup-close" class="maca-menu-close maca-menu-close--popup" aria-label="' . esc_attr__('Close menu', 'maca-restu-pro') . '">&times;</button>';
                echo '<div class="maca-popup-content" id="maca-popup-content"></div>';
                echo '</div>';
                echo '<div class="maca-popup-overlay" id="maca-popup-overlay"></div>';
            }

            echo '
    <script>
        const websiteDisplayMode = "' . esc_js($website_display_mode) . '";
        const qrLayoutMode = "' . esc_js($qr_display_mode) . '";
        const macaQrAjaxUrl = "' . esc_url(admin_url('admin-ajax.php')) . '";
        const macaQrNonce = "' . esc_js(wp_create_nonce('maca_menu_nonce')) . '";
        const macaQrStrings = {
            loading: "' . esc_js(__('Loading...', 'maca-restu-pro')) . '",
            noMenu: "' . esc_js(__('No active menu available for this category.', 'maca-restu-pro')) . '",
            error: "' . esc_js(__('Error loading menu.', 'maca-restu-pro')) . '"
        };

        function renderMenuInto(container, data) {
            if (!data || !data.success || !data.data) {
                container.innerHTML = "<p style=\"text-align: center; padding: 50px;\">" + macaQrStrings.noMenu + "</p>";
                return;
            }

            if (data.data.html) {
                container.innerHTML = data.data.html;
                return;
            }

            if (data.data.file_type === "pdf" && data.data.file_url && window.MacaMenulistPdf) {
                container.innerHTML = "";
                MacaMenulistPdf.render(container, data.data.file_url, data.data.title || "", {
                    loadingText: macaQrStrings.loading,
                    showTitle: false
                });
                return;
            }

            container.innerHTML = "<p style=\"text-align: center; padding: 50px;\">" + macaQrStrings.noMenu + "</p>";
        }

        function fetchCategoryMenu(categoryId) {
            const body = new URLSearchParams({
                action: "maca_load_category_menu",
                category_id: String(categoryId),
                nonce: macaQrNonce,
                qr_page: "1"
            });

            return fetch(macaQrAjaxUrl, {
                method: "POST",
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded"
                },
                body: body.toString()
            }).then(function(response) {
                if (!response.ok) {
                    throw new Error("HTTP " + response.status);
                }
                return response.json();
            });
        }

        function loadMenu(categoryId) {
            if (websiteDisplayMode === "new_page") {
                const viewerUrl = macaQrAjaxUrl
                    + "?action=maca_load_category_menu"
                    + "&category_id=" + encodeURIComponent(categoryId)
                    + "&nonce=" + encodeURIComponent(macaQrNonce)
                    + "&render_html=1"
                    + "&qr_page=1";
                const newTab = window.open(viewerUrl, "_blank");
                if (!newTab) {
                    window.location.href = viewerUrl;
                }
                return;
            }

            let container;
            const menuContainer = document.querySelector(".menu-container");
            const closeButton = document.getElementById("close-button");
            const popup = document.getElementById("maca-menu-popup");
            const overlay = document.getElementById("maca-popup-overlay");
            const popupClose = document.getElementById("maca-qr-popup-close");

            if (websiteDisplayMode === "popup") {
                container = document.getElementById("maca-popup-content");
                if (!container || !popup || !overlay) {
                    return;
                }
                popup.classList.add("active");
                overlay.classList.add("active");
                if (popupClose) {
                    popupClose.style.display = "flex";
                }
            } else {
                container = document.getElementById("menu-content");
                if (!container) {
                    return;
                }
                container.style.display = "block";
                container.classList.add("active");
                if (closeButton) {
                    closeButton.style.display = "flex";
                }
                if (qrLayoutMode === "full_page" && menuContainer) {
                    menuContainer.style.display = "none";
                }
            }

            container.innerHTML = "<p style=\"text-align: center; padding: 50px;\">" + macaQrStrings.loading + "</p>";

            fetchCategoryMenu(categoryId)
                .then(function(data) {
                    renderMenuInto(container, data);
                    if (websiteDisplayMode !== "popup") {
                        container.style.display = "block";
                    }
                })
                .catch(function(error) {
                    container.innerHTML = "<p style=\"text-align: center; padding: 50px;\">" + macaQrStrings.error + " " + error.message + "</p>";
                });
        }

        function closeMenu() {
            const menuContainer = document.querySelector(".menu-container");
            const menuContent = document.getElementById("menu-content");
            const closeButton = document.getElementById("close-button");
            const popup = document.getElementById("maca-menu-popup");
            const overlay = document.getElementById("maca-popup-overlay");
            const popupContent = document.getElementById("maca-popup-content");
            const popupClose = document.getElementById("maca-qr-popup-close");

            if (websiteDisplayMode === "popup") {
                if (popup) {
                    popup.classList.remove("active");
                }
                if (overlay) {
                    overlay.classList.remove("active");
                }
                if (popupContent) {
                    popupContent.innerHTML = "";
                }
                if (popupClose) {
                    popupClose.style.display = "none";
                }
                return;
            }

            if (menuContent) {
                menuContent.style.display = "none";
                menuContent.classList.remove("active");
                menuContent.innerHTML = "";
            }
            if (closeButton) {
                closeButton.style.display = "none";
            }
            if (menuContainer) {
                menuContainer.style.display = "block";
            }
        }

        document.querySelectorAll(".category-button").forEach(function(button) {
            button.addEventListener("click", function() {
                loadMenu(button.getAttribute("data-category-id"));
            });
        });

        const closeButton = document.getElementById("close-button");
        if (closeButton) {
            closeButton.addEventListener("click", closeMenu);
        }
        const popupOverlay = document.getElementById("maca-popup-overlay");
        if (popupOverlay) {
            popupOverlay.addEventListener("click", closeMenu);
        }
        const popupClose = document.getElementById("maca-qr-popup-close");
        if (popupClose) {
            popupClose.addEventListener("click", closeMenu);
        }
    </script>
</body>
</html>';
        // phpcs:enable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Security.EscapeOutput.OutputNotEscaped

        exit;
    }

    /**
     * Handle public takeaway menu page (/hamtmat/ by default).
     */
    public function handle_takeaway_menu_page() {
        if (!function_exists('maca_menulist_is_takeaway_menu_request') || !maca_menulist_is_takeaway_menu_request()) {
            return;
        }

        if (!maca_menulist_is_public_dishes_mode() || !maca_menulist_takeaway_ordering_enabled()) {
            status_header(404);
            nocache_headers();
            exit;
        }

        if (function_exists('maca_menulist_legal_blocks_frontend') && maca_menulist_legal_blocks_frontend()) {
            maca_menulist_legal_render_blocked_page();
        }

        maca_menulist_load_textdomain();
        maca_menulist_set_guest_order_channel('takeaway');

        status_header(200);
        nocache_headers();

        $this->render_takeaway_dishes_page();
    }

    /**
     * Render takeaway menu page (dish mode).
     */
    private function render_takeaway_dishes_page() {
        $page_title = maca_menulist_get_takeaway_guest_page_title();
        $campaign_title = maca_menulist_get_active_campaign_menu_title(
            array(
                'qr_schedule' => true,
                'takeaway_menu' => true,
            )
        );
        if ($campaign_title !== '' && maca_menulist_campaign_exclusive_mode_enabled()) {
            $page_title = $campaign_title;
        }

        $dish_theme_body_class = function_exists('maca_menulist_get_dish_menu_theme_body_class')
            ? maca_menulist_get_dish_menu_theme_body_class()
            : '';

        // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Security.EscapeOutput.OutputNotEscaped
        echo '<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
    <title>' . esc_html($page_title) . '</title>
    <link rel="stylesheet" href="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/css/style.css?ver=' . MACA_MENULIST_VERSION) . '">
    <link rel="stylesheet" href="' . esc_url(maca_menulist_get_dish_menu_themes_stylesheet_url()) . '">
</head>
<body class="maca-takeaway-dish-page' . ($dish_theme_body_class !== '' ? ' ' . esc_attr($dish_theme_body_class) : '') . '">
    <div class="menu-container">';

        maca_menulist_render_qr_menu_logo();

        echo '<h1 class="menu-title">' . esc_html($page_title) . '</h1>';
        echo '<div class="maca-menulist-wrap maca-menulist-wrap-takeaway">';
        maca_menulist_render_dish_menu('takeaway', true);
        echo '</div></div>';

        if (maca_menulist_is_public_dishes_mode()) {
            echo '<script>window.macaMenulistDish = ' . wp_json_encode(maca_menulist_get_dish_menu_script_config()) . ';</script>';
        }
        if (maca_menulist_table_order_enabled()) {
            echo '<script>window.macaMenulistTableOrder = ' . wp_json_encode(maca_menulist_get_table_order_script_config('takeaway')) . ';</script>';
        }
        echo '<script src="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/js/dish-menu.js?ver=' . MACA_MENULIST_VERSION) . '"></script>'; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Standalone takeaway page exits before theme output.
        if (maca_menulist_table_order_enabled()) {
            echo '<script src="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/js/table-order.js?ver=' . MACA_MENULIST_VERSION) . '"></script>'; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Standalone takeaway page exits before theme output.
        }
        echo '</body></html>';
        // phpcs:enable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Security.EscapeOutput.OutputNotEscaped

        exit;
    }

    /**
     * Render QR page for dish mode (full menu list, no category buttons).
     */
    private function render_qr_dishes_page() {
        $qr_page_title = maca_menulist_get_qr_menu_page_title();
        $campaign_title = maca_menulist_get_active_campaign_menu_title(
            array(
                'qr_schedule' => true,
            )
        );
        if ($campaign_title !== '' && maca_menulist_campaign_exclusive_mode_enabled()) {
            $qr_page_title = $campaign_title;
        }

        $dish_theme_body_class = function_exists('maca_menulist_get_dish_menu_theme_body_class')
            ? maca_menulist_get_dish_menu_theme_body_class()
            : '';

        // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.Security.EscapeOutput.OutputNotEscaped
        echo '<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
    <title>' . esc_html($qr_page_title) . '</title>
    <link rel="stylesheet" href="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/css/style.css?ver=' . MACA_MENULIST_VERSION) . '">
    <link rel="stylesheet" href="' . esc_url(maca_menulist_get_dish_menu_themes_stylesheet_url()) . '">
</head>
<body class="maca-qr-dish-page' . ($dish_theme_body_class !== '' ? ' ' . esc_attr($dish_theme_body_class) : '') . '">
    <div class="menu-container">';

        maca_menulist_render_qr_menu_logo();

        echo '<h1 class="menu-title">' . esc_html($qr_page_title) . '</h1>';

        echo '<div class="maca-menulist-wrap maca-menulist-wrap-qr">';

        maca_menulist_render_dish_menu('qr', false);

        echo '</div>';
        echo '</div>';

        maca_menulist_render_table_order_ui();

        if (maca_menulist_is_public_dishes_mode()) {
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON config for standalone QR page.
            echo '<script>window.macaMenulistDish = ' . wp_json_encode(maca_menulist_get_dish_menu_script_config()) . ';</script>';
        }
        if (maca_menulist_table_order_enabled()) {
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON config for standalone QR page.
            echo '<script>window.macaMenulistTableOrder = ' . wp_json_encode(maca_menulist_get_table_order_script_config('qr')) . ';</script>';
        }
        // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Standalone QR page exits before theme output.
        echo '<script src="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/js/dish-menu.js?ver=' . MACA_MENULIST_VERSION) . '"></script>';
        if (maca_menulist_table_order_enabled()) {
            // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Standalone QR page exits before theme output.
            echo '<script src="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/js/table-order.js?ver=' . MACA_MENULIST_VERSION) . '"></script>';
        }
        echo '
</body>
</html>';
        // phpcs:enable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.Security.EscapeOutput.OutputNotEscaped

        exit;
    }

    /**
     * Shortcode for table reservation form.
     *
     * @param array<string, mixed>|string $atts Shortcode attributes.
     * @return string
     */
    public function render_table_booking_shortcode($atts) {
        $atts = is_array($atts) ? $atts : array();
        $this->register_frontend_assets();

        if (maca_menulist_table_booking_enabled()) {
            maca_menulist_register_table_booking_assets();
            wp_enqueue_script('maca-menulist-table-booking');
        }

        return maca_menulist_render_table_booking_form($atts);
    }

    /**
     * Shortcode for opening hours.
     *
     * @param array<string, mixed>|string $atts Shortcode attributes.
     * @return string
     */
    public function render_opening_hours_shortcode($atts) {
        $atts = is_array($atts) ? $atts : array();
        $this->register_frontend_assets();

        return maca_menulist_render_opening_hours($atts);
    }

    /**
     * AJAX: available time slots for a date.
     */
    public function ajax_get_booking_slots() {
        maca_menulist_db_ensure_table_booking_tables();

        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';

        if (!wp_verify_nonce($nonce, 'maca_table_booking')) {
            wp_send_json_error(array('message' => __('Invalid request.', 'maca-restu-pro')));
        }

        if (!maca_menulist_table_booking_enabled()) {
            wp_send_json_error(array('message' => __('Table Reservation is not enabled.', 'maca-restu-pro')));
        }

        $date = isset($_POST['booking_date']) ? sanitize_text_field(wp_unslash($_POST['booking_date'])) : '';
        $party_size = isset($_POST['party_size']) ? max(1, (int) wp_unslash($_POST['party_size'])) : 2;

        $use_waitlist_hours = false;
        if (!maca_menulist_is_date_bookable($date)) {
            if (maca_menulist_table_booking_waitlist_enabled() && maca_menulist_is_date_waitlist_eligible($date)) {
                $use_waitlist_hours = true;
            } else {
                wp_send_json_error(
                    array(
                        'message' => maca_menulist_table_booking_get_unavailable_message($date, $party_size),
                    )
                );
            }
        }

        if (!maca_menulist_table_booking_has_active_tables()) {
            wp_send_json_error(
                array(
                    'message' => maca_menulist_table_booking_get_unavailable_message($date, $party_size),
                )
            );
        }

        if ($use_waitlist_hours) {
            $slots = maca_menulist_get_waitlist_time_slots($date);
        } else {
            $slots = maca_menulist_get_guest_booking_time_slots($date, $party_size);
        }

        if (empty($slots)) {
            wp_send_json_success(
                array(
                    'slots' => array(),
                    'message' => maca_menulist_table_booking_get_unavailable_message($date, $party_size),
                    'waitlist_only' => $use_waitlist_hours,
                )
            );
        }

        wp_send_json_success(
            array(
                'slots' => $slots,
                'waitlist_only' => $use_waitlist_hours,
            )
        );
    }

    /**
     * AJAX: available tables for date/time.
     */
    public function ajax_get_booking_tables() {
        maca_menulist_db_ensure_table_booking_tables();

        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';

        if (!wp_verify_nonce($nonce, 'maca_table_booking')) {
            wp_send_json_error(array('message' => __('Invalid request.', 'maca-restu-pro')));
        }

        if (!maca_menulist_table_booking_enabled()) {
            wp_send_json_error(array('message' => __('Table Reservation is not enabled.', 'maca-restu-pro')));
        }

        $date = isset($_POST['booking_date']) ? sanitize_text_field(wp_unslash($_POST['booking_date'])) : '';
        $time = isset($_POST['booking_time']) ? sanitize_text_field(wp_unslash($_POST['booking_time'])) : '';
        $party_size = isset($_POST['party_size']) ? max(1, (int) wp_unslash($_POST['party_size'])) : 2;

        $tables = maca_menulist_get_available_tables($date, $time, $party_size);
        $payload = array();

        foreach ($tables as $table) {
            $payload[] = array(
                'id' => (int) $table->id,
                'table_number' => $table->table_number,
                'seats' => (int) $table->seats,
            );
        }

        if (empty($payload)) {
            wp_send_json_success(
                array(
                    'tables' => array(),
                    'message' => maca_menulist_table_booking_get_unavailable_message($date, $party_size),
                )
            );
        }

        wp_send_json_success(array('tables' => $payload));
    }

    /**
     * AJAX: submit a table reservation request.
     */
    public function ajax_submit_table_booking() {
        maca_menulist_db_ensure_table_booking_tables();

        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';

        if (!wp_verify_nonce($nonce, 'maca_table_booking')) {
            wp_send_json_error(array('message' => __('Invalid request.', 'maca-restu-pro')));
        }

        if (!maca_menulist_table_booking_enabled()) {
            wp_send_json_error(array('message' => __('Table Reservation is not enabled.', 'maca-restu-pro')));
        }

        $date = isset($_POST['booking_date']) ? sanitize_text_field(wp_unslash($_POST['booking_date'])) : '';
        $time = isset($_POST['booking_time']) ? sanitize_text_field(wp_unslash($_POST['booking_time'])) : '';
        $party_size = isset($_POST['party_size']) ? max(1, (int) wp_unslash($_POST['party_size'])) : 2;
        $table_id = isset($_POST['table_id']) ? absint(wp_unslash($_POST['table_id'])) : 0;
        $guest_name = isset($_POST['guest_name']) ? sanitize_text_field(wp_unslash($_POST['guest_name'])) : '';
        $guest_email = isset($_POST['guest_email']) ? sanitize_email(wp_unslash($_POST['guest_email'])) : '';
        $guest_phone = isset($_POST['guest_phone']) ? sanitize_text_field(wp_unslash($_POST['guest_phone'])) : '';
        $guest_note = isset($_POST['guest_note']) ? sanitize_textarea_field(wp_unslash($_POST['guest_note'])) : '';

        $validation = maca_menulist_validate_table_booking_submission(
            array(
                'booking_date' => $date,
                'booking_time' => $time,
                'party_size' => $party_size,
                'table_id' => $table_id,
                'guest_name' => $guest_name,
                'guest_email' => $guest_email,
                'guest_phone' => $guest_phone,
            )
        );

        if (is_wp_error($validation)) {
            wp_send_json_error(array('message' => $validation->get_error_message()));
        }

        $captcha_token = '';
        if (isset($_POST['captcha_token'])) {
            $captcha_token = sanitize_text_field(wp_unslash($_POST['captcha_token']));
        } elseif (isset($_POST['g-recaptcha-response'])) {
            $captcha_token = sanitize_text_field(wp_unslash($_POST['g-recaptcha-response']));
        }

        $captcha_check = maca_menulist_verify_table_booking_captcha($captcha_token);
        if (is_wp_error($captcha_check)) {
            wp_send_json_error(array('message' => $captcha_check->get_error_message()));
        }

        if (maca_menulist_table_booking_uses_best_fit_assignment()) {
            $best_table = maca_menulist_pick_best_available_table($date, $time, $party_size);

            if (!$best_table) {
                wp_send_json_error(
                    array(
                        'message' => maca_menulist_table_booking_get_unavailable_message($date, $party_size),
                    )
                );
            }

            $table_id = (int) $best_table->id;
        } else {
            $available = maca_menulist_get_available_tables($date, $time, $party_size);
            $table_ok = false;

            foreach ($available as $table) {
                if ((int) $table->id === $table_id) {
                    $table_ok = true;
                    break;
                }
            }

            if (!$table_ok) {
                if (empty($available)) {
                    wp_send_json_error(
                        array(
                            'message' => maca_menulist_table_booking_get_unavailable_message($date, $party_size),
                        )
                    );
                }

                wp_send_json_error(array('message' => __('The selected table is no longer available.', 'maca-restu-pro')));
            }
        }

        $result = maca_menulist_db_insert_booking(
            array(
                'table_id' => $table_id,
                'booking_date' => $date,
                'booking_time' => $time,
                'party_size' => $party_size,
                'guest_name' => $guest_name,
                'guest_email' => $guest_email,
                'guest_phone' => $guest_phone,
                'guest_note' => $guest_note,
            )
        );

        if (!$result) {
            wp_send_json_error(array('message' => __('Could not save the booking. Please try again.', 'maca-restu-pro')));
        }

        maca_menulist_send_booking_email((int) $result['id'], 'received');

        if (function_exists('maca_menulist_booking_log_created')) {
            maca_menulist_booking_log_created((int) $result['id'], 'guest');
        }

        /**
         * Fires after a guest submits a table reservation.
         *
         * @param int $booking_id Booking ID.
         */
        do_action('maca_menulist_booking_created', (int) $result['id']);

        wp_send_json_success(array('booking_id' => (int) $result['id']));
    }

    /**
     * AJAX: join the waitlist (no table required).
     */
    public function ajax_submit_table_booking_waitlist() {
        maca_menulist_db_ensure_table_booking_tables();

        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';

        if (!wp_verify_nonce($nonce, 'maca_table_booking')) {
            wp_send_json_error(array('message' => __('Invalid request.', 'maca-restu-pro')));
        }

        if (!maca_menulist_table_booking_enabled() || !maca_menulist_table_booking_waitlist_enabled()) {
            wp_send_json_error(array('message' => __('Waitlist is not available.', 'maca-restu-pro')));
        }

        $captcha_token = '';
        if (isset($_POST['captcha_token'])) {
            $captcha_token = sanitize_text_field(wp_unslash($_POST['captcha_token']));
        } elseif (isset($_POST['g-recaptcha-response'])) {
            $captcha_token = sanitize_text_field(wp_unslash($_POST['g-recaptcha-response']));
        }

        $captcha_check = maca_menulist_verify_table_booking_captcha($captcha_token);
        if (is_wp_error($captcha_check)) {
            wp_send_json_error(array('message' => $captcha_check->get_error_message()));
        }

        $result = maca_menulist_create_waitlist_booking(
            array(
                'booking_date' => isset($_POST['booking_date']) ? sanitize_text_field(wp_unslash($_POST['booking_date'])) : '',
                'booking_time' => isset($_POST['booking_time']) ? sanitize_text_field(wp_unslash($_POST['booking_time'])) : '',
                'party_size' => isset($_POST['party_size']) ? max(1, (int) wp_unslash($_POST['party_size'])) : 2,
                'guest_name' => isset($_POST['guest_name']) ? sanitize_text_field(wp_unslash($_POST['guest_name'])) : '',
                'guest_email' => isset($_POST['guest_email']) ? sanitize_email(wp_unslash($_POST['guest_email'])) : '',
                'guest_phone' => isset($_POST['guest_phone']) ? sanitize_text_field(wp_unslash($_POST['guest_phone'])) : '',
                'guest_note' => isset($_POST['guest_note']) ? sanitize_textarea_field(wp_unslash($_POST['guest_note'])) : '',
            ),
            'guest'
        );

        if (is_wp_error($result)) {
            wp_send_json_error(array('message' => $result->get_error_message()));
        }

        wp_send_json_success(array('booking_id' => (int) $result));
    }

    /**
     * Guest cancellation page (link from booking emails).
     */
    public function handle_booking_cancel_page() {
        if (!get_query_var('maca_booking_cancel')) {
            return;
        }

        if (!maca_menulist_table_booking_enabled() || !maca_menulist_table_booking_guest_cancel_enabled()) {
            wp_die(esc_html__('Booking cancellation is not available.', 'maca-restu-pro'));
        }

        $token = isset($_GET['token']) ? sanitize_text_field(wp_unslash($_GET['token'])) : '';
        if ($token === '') {
            wp_die(esc_html__('Invalid cancellation link.', 'maca-restu-pro'));
        }

        $booking = maca_menulist_db_get_booking_by_token($token);
        $error_message = '';
        $cancelled = false;

        // phpcs:disable WordPress.Security.NonceVerification.Missing
        if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['maca_cancel_booking'])) {
            if (!isset($_POST['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_wpnonce'])), 'maca_cancel_booking_' . $token)) {
                $error_message = __('Invalid request. Please try again.', 'maca-restu-pro');
            } else {
                $result = maca_menulist_cancel_booking_by_guest($token);
                if (is_wp_error($result)) {
                    $error_message = $result->get_error_message();
                } else {
                    $cancelled = true;
                    $booking = maca_menulist_db_get_booking_by_token($token);
                }
            }
        }
        // phpcs:enable WordPress.Security.NonceVerification.Missing

        status_header(200);
        nocache_headers();

        $restaurant = maca_menulist_get_booking_restaurant_name();
        $title = __('Cancel booking', 'maca-restu-pro');
        $datetime = $booking ? maca_menulist_format_booking_datetime($booking) : '';
        $can_cancel = $booking && maca_menulist_guest_can_cancel_booking($booking);

        // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.Security.EscapeOutput.OutputNotEscaped
        echo '<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>' . esc_html($title) . '</title>
    <link rel="stylesheet" href="' . esc_url(MACA_MENULIST_PLUGIN_URL . 'assets/css/style.css?ver=' . MACA_MENULIST_VERSION) . '">
</head>
<body class="maca-booking-cancel-page">
    <div class="maca-booking-cancel-panel">
        <h1>' . esc_html($title) . '</h1>
        <p class="maca-booking-cancel-restaurant">' . esc_html($restaurant) . '</p>';

        if ($cancelled) {
            echo '<p class="maca-booking-cancel-success">' . esc_html__('Your booking has been cancelled. A confirmation email has been sent to you.', 'maca-restu-pro') . '</p>';
        } elseif (!$booking) {
            echo '<p class="maca-booking-cancel-error">' . esc_html__('Booking not found.', 'maca-restu-pro') . '</p>';
        } elseif ($booking->status === 'cancelled') {
            echo '<p class="maca-booking-cancel-info">' . esc_html__('This booking has already been cancelled.', 'maca-restu-pro') . '</p>';
        } elseif (!$can_cancel) {
            echo '<p class="maca-booking-cancel-error">' . esc_html__('This booking can no longer be cancelled online. Please contact the restaurant.', 'maca-restu-pro') . '</p>';
        } else {
            if ($error_message !== '') {
                echo '<p class="maca-booking-cancel-error">' . esc_html($error_message) . '</p>';
            }

            echo '<dl class="maca-booking-cancel-details">
                <dt>' . esc_html__('Name', 'maca-restu-pro') . '</dt>
                <dd>' . esc_html($booking->guest_name) . '</dd>
                <dt>' . esc_html__('Date & time', 'maca-restu-pro') . '</dt>
                <dd>' . esc_html($datetime) . '</dd>
                <dt>' . esc_html__('Guests', 'maca-restu-pro') . '</dt>
                <dd>' . esc_html((string) (int) $booking->party_size) . '</dd>
            </dl>
            <form method="post" class="maca-booking-cancel-form">
                ' . wp_nonce_field('maca_cancel_booking_' . $token, '_wpnonce', true, false) . '
                <input type="hidden" name="maca_cancel_booking" value="1">
                <button type="submit" class="maca-category-button maca-booking-cancel-submit" onclick="return confirm(' . wp_json_encode(__('Cancel this booking?', 'maca-restu-pro')) . ');">
                    <span class="maca-category-name">' . esc_html__('Cancel booking', 'maca-restu-pro') . '</span>
                </button>
            </form>';
        }

        echo '</div>
</body>
</html>';
        // phpcs:enable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet, WordPress.Security.EscapeOutput.OutputNotEscaped

        exit;
    }
}
