<?php
/*
Plugin Name: Meals28 — Variable Products (Final)
Description: Variable Products extension with robust menu lookup and embedded Manage UI. Safe fallback handling.
Version: 1.2
Author: Assistant (generated)
*/

if ( ! defined( 'ABSPATH' ) ) exit;

// --- Require WooCommerce ---
add_action( 'plugins_loaded', 'm28_final_init', 5 );
function m28_final_init() {
    if ( ! class_exists( 'WooCommerce' ) ) {
        add_action( 'admin_notices', function() {
            echo '<div class="notice notice-error"><p><strong>Meals28 — Variable Products (Final)</strong>: WooCommerce must be active for this plugin to work.</p></div>';
        } );
        return;
    }
    m28_final_setup();
}

function m28_final_setup() {
    if ( defined( 'M28_FINAL_LOADED' ) ) return;
    define( 'M28_FINAL_LOADED', true );
    if ( ! defined( 'M28_FINAL_PRODUCT_IDS' ) ) {
        define( 'M28_FINAL_PRODUCT_IDS', array(91, 300, 306));
    }
    if ( ! defined( 'M28_FINAL_VARIATION_MAP' ) ) define( 'M28_FINAL_VARIATION_MAP', serialize(array(
            92 => 28,     // Breakfast 3 days
            93 => 3,    // Breakfast 28 days
            321 => 3,    // Lunch 3 days
            320 => 28,   // Lunch 28 days
            307 => 3,    // Dinner 3 days
            308 => 28    // Dinner 28 days
        )) );
    if ( ! defined( 'M28_FINAL_NONCE' ) ) define( 'M28_FINAL_NONCE', 'm28_final_nonce' );

    register_activation_hook( __FILE__, 'm28_final_activate' );
    function m28_final_activate() {
        global $wpdb;
        $charset_collate = $wpdb->get_charset_collate();
        $table1 = $wpdb->prefix . 'm28_orders_variable_items';
        $table2 = $wpdb->prefix . 'm28_variable_item_dates';
        $sql1 = "CREATE TABLE IF NOT EXISTS $table1 (
            id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
            user_id BIGINT UNSIGNED NOT NULL,
            order_id BIGINT UNSIGNED NOT NULL,
            order_item_id BIGINT UNSIGNED NOT NULL,
            product_id BIGINT UNSIGNED NOT NULL,
            variation_id BIGINT UNSIGNED DEFAULT NULL,
            purchase_date DATETIME NOT NULL,
            start_date DATE NOT NULL,
            purchased_days INT NOT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            KEY (user_id),
            KEY (order_id),
            KEY (order_item_id)
        ) $charset_collate;";
        $sql2 = "CREATE TABLE IF NOT EXISTS $table2 (
            id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
            variable_item_id BIGINT UNSIGNED NOT NULL,
            delivery_date DATE NOT NULL,
            menu_key VARCHAR(191) DEFAULT NULL,
            status ENUM('pending','delivered','skipped') NOT NULL DEFAULT 'pending',
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            KEY (variable_item_id, delivery_date)
        ) $charset_collate;";
        require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
        dbDelta( $sql1 );
        dbDelta( $sql2 );
    }

    // Helper: variation map
    function m28_final_get_variation_days_map() {
        $map = @unserialize( M28_FINAL_VARIATION_MAP );
        if ( ! is_array( $map ) ) $map = array();
        return $map;
    }

    // Order hooks
    add_action( 'woocommerce_order_status_processing', 'm28_final_create_schedule', 20 );
    add_action( 'woocommerce_order_status_completed', 'm28_final_create_schedule', 20 );
    // Helper: infer purchased days from order item
    function m28_final_get_purchased_days_from_item( WC_Order_Item_Product $item ) {
        // 1) Try old variation ID map as a fallback (if it happens to be correct)
        $variation_id = $item->get_variation_id();
        $map = m28_final_get_variation_days_map();
        if ( $variation_id && isset( $map[ $variation_id ] ) ) {
            return (int) $map[ $variation_id ];
        }

        // 2) Try to read from item name, e.g. "Breakfast - 3 Days" or "Lunch - 28 Days @ 20% OFF"
        $label = strtolower( $item->get_name() );
        if ( preg_match( '/(\d+)\s*day/', $label, $m ) ) {
            return (int) $m[1];
        }

        // 3) Optionally, look into variation attributes text as backup
        $attrs = $item->get_formatted_meta_data( '' );
        if ( ! empty( $attrs ) ) {
            $attr_text = strtolower( wc_implode_html_attributes( array_map( function( $meta ) {
                return $meta->display_value;
            }, $attrs ) ) );
            if ( preg_match( '/(\d+)\s*day/', $attr_text, $m2 ) ) {
                return (int) $m2[1];
            }
        }

        // If nothing matched, treat as non-package
        return 0;
    }

    function m28_final_create_schedule( $order_id ) {
        if ( ! $order_id ) return;
        $order = wc_get_order( $order_id );
        if ( ! $order ) return;
        $user_id = $order->get_user_id() ?: 0;
        $order_date_obj = $order->get_date_created();
        $order_date_str = $order_date_obj ? $order_date_obj->date_i18n( 'Y-m-d H:i:s' ) : current_time( 'mysql' );
        $start_date = date_i18n( 'Y-m-d', strtotime( date_i18n( 'Y-m-d', strtotime( $order_date_str ) ) . ' +1 day' ) );
        $days_map = m28_final_get_variation_days_map();
        global $wpdb;
        $table_items = $wpdb->prefix . 'm28_orders_variable_items';
        $table_dates = $wpdb->prefix . 'm28_variable_item_dates';
        foreach ( $order->get_items() as $item_id => $item ) {
            if ( ! $item instanceof WC_Order_Item_Product ) {
                continue;
            }

            $product_id = $item->get_product_id();

            // 🔑 NEW: Detect days from item instead of hard-coded variation IDs
            $purchased_days = m28_final_get_purchased_days_from_item( $item );

            // If this order line doesn't look like a days-based package, skip
            if ( $purchased_days <= 0 ) {
                continue;
            }

            // (Optional) If you still want to restrict to some product IDs, uncomment:
            // if ( ! in_array( $product_id, M28_FINAL_PRODUCT_IDS ) ) {
            //     continue;
            // }

            // Avoid duplicate schedule for same order item
            $exists = $wpdb->get_var( $wpdb->prepare(
                "SELECT id FROM $table_items WHERE order_item_id = %d",
                $item_id
            ) );
            if ( $exists ) {
                continue;
            }

            // Insert parent package row
            $wpdb->insert(
                $table_items,
                array(
                    'user_id'       => $user_id,
                    'order_id'      => $order_id,
                    'order_item_id' => $item_id,
                    'product_id'    => $product_id,
                    'variation_id'  => $item->get_variation_id(),
                    'purchase_date' => $order_date_str,
                    'start_date'    => $start_date,
                    'purchased_days'=> $purchased_days,
                ),
                array( '%d','%d','%d','%d','%d','%s','%s','%d' )
            );

            $variable_item_id = $wpdb->insert_id;
            if ( ! $variable_item_id ) {
                continue;
            }

            // Create day-wise schedule
            for ( $i = 0; $i < $purchased_days; $i++ ) {
                $dd = date_i18n( 'Y-m-d', strtotime( $start_date . " +{$i} days" ) );
                $status = ( strtotime( $dd ) < strtotime( date_i18n( 'Y-m-d' ) ) ) ? 'delivered' : 'pending';

                $wpdb->insert(
                    $table_dates,
                    array(
                        'variable_item_id' => $variable_item_id,
                        'delivery_date'    => $dd,
                        'menu_key'         => $dd,
                        'status'           => $status,
                    ),
                    array( '%d','%s','%s','%s' )
                );
            }
        }
    }

    // Account endpoint
    add_action( 'init', 'm28_final_add_endpoint' );
    function m28_final_add_endpoint() { add_rewrite_endpoint( 'variable-products', EP_PAGES ); }
    add_filter( 'query_vars', 'm28_final_query_vars', 0 );
    function m28_final_query_vars( $vars ) { $vars[] = 'variable-products'; return $vars; }
    add_filter( 'woocommerce_account_menu_items', 'm28_final_account_menu_items', 99 );
    function m28_final_account_menu_items( $items ) {
        $new_items = array();
        foreach ( $items as $key => $label ) {
            $new_items[ $key ] = $label;
            if ( $key === 'dashboard' ) $new_items['variable-products'] = 'Meals Package';
        }
        if ( ! isset( $new_items['variable-products'] ) ) $new_items['variable-products'] = 'Variable Products';
        return $new_items;
    }

    function m28_final_account_endpoint() {
        if ( ! is_user_logged_in() ) { echo '<p>Please log in to view your variable products.</p>'; return; }
        $user_id = get_current_user_id();
        global $wpdb;
        $table_items = $wpdb->prefix . 'm28_orders_variable_items';
        $table_dates = $wpdb->prefix . 'm28_variable_item_dates';
        $items = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_items WHERE user_id = %d ORDER BY created_at DESC", $user_id ) );
        echo '<h2>Your Meals Package</h2>';
        if ( empty( $items ) ) { echo '<p>You have not purchased any variable products yet.</p>'; return; }
        echo '<table class="m28-table" style="width:100%;border-collapse:collapse;">';
        echo '<thead><tr><th>Product</th><th>Purchased On</th><th>Plan</th><th>Remaining Days</th><th>Manage</th></tr></thead><tbody>';
        foreach ( $items as $it ) {
            $prod = get_post( $it->product_id );
            $product_name = $prod ? esc_html( $prod->post_title ) : 'Product #' . intval( $it->product_id );
            $variation = intval( $it->variation_id );
            $map = m28_final_get_variation_days_map();
            $plan = isset($map[$variation]) ? $map[$variation] . ' days' : 'Plan';
            $remaining = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $table_dates WHERE variable_item_id = %d AND status IN ('pending','skipped')", $it->id ) );
            $manage_url = esc_url( wc_get_account_endpoint_url( 'variable-products' ) . '?m28_item=' . intval( $it->id ) . '&action=manage' );
            echo '<tr style="border-top:1px solid #ddd;"><td><a href="' . get_permalink( $it->product_id ) . '">' . $product_name . '</a></td><td>' . esc_html( date_i18n( get_option('date_format'), strtotime( $it->purchase_date ) ) ) . '</td><td>' . esc_html( $plan ) . '</td><td>' . intval( $remaining ) . '</td><td><a href="' . $manage_url . '">Manage</a></td></tr>';
        }
        echo '</tbody></table>';
    }

    // Embedded manage rendering
    function m28_final_render_manage_page( $item_id ) {
        if ( ! is_user_logged_in() ) { echo '<p>Please log in.</p>'; return; }
        $user_id = get_current_user_id();
        global $wpdb;
        $table_items = $wpdb->prefix . 'm28_orders_variable_items';
        $table_dates = $wpdb->prefix . 'm28_variable_item_dates';
        $item = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_items WHERE id = %d", $item_id ) );
        if ( ! $item || intval( $item->user_id ) !== $user_id ) { echo '<p>Invalid item or permission denied</p>'; return; }
        $dates = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_dates WHERE variable_item_id = %d ORDER BY delivery_date ASC", $item_id ) );

        echo '<div class="m28-manage-wrap">';
        echo '<h2 class="m28-manage-title">Manage: ' . esc_html( get_the_title( $item->product_id ) ) . '</h2>';
        echo '<p class="m28-manage-subtitle">Plan: <strong>' . intval( $item->purchased_days ) . ' days</strong> — Start: <strong>' . esc_html( date_i18n( get_option("date_format"), strtotime( $item->start_date ) ) ) . '</strong></p>';

        echo '<div class="m28-card"><div class="m28-card-body">';
        if ( empty( $dates ) ) { echo '<p>No scheduled dates found.</p>'; }
        else {
            echo '<div class="m28-table-responsive"><table class="m28-table"><thead><tr><th>Date</th><th>Menu</th><th style="width:120px;">Status</th><th style="width:140px;">Action</th></tr></thead><tbody>';
            foreach ( $dates as $d ) {
                $date_display = esc_html( date_i18n( 'D, d M Y', strtotime( $d->delivery_date ) ) );
                $menu_html = m28_final_get_menu_html_for_date( $d->delivery_date, $item->product_id );
                $status_label = '<span class="m28-badge m28-badge-' . esc_attr( $d->status ) . '">' . esc_html( ucfirst( $d->status ) ) . '</span>';
                $action_html = '';
                $today = date_i18n( 'Y-m-d' );
                if ( $d->status === 'pending' && strtotime( $d->delivery_date ) >= strtotime( date_i18n('Y-m-d', strtotime('+1 day')) ) ) {
                    $action_html = '<button class="m28-btn m28-btn-skip" data-date-id="' . intval( $d->id ) . '"> Skip</button>';
                } elseif ( $d->status === 'skipped' ) {
                    if ( strtotime( $d->delivery_date ) > strtotime( $today ) ) {
                        $action_html = '<button class="m28-btn m28-btn-revert" data-date-id="' . intval( $d->id ) . '"> Remove Skip</button>';
                    }
                }
                echo '<tr class="m28-row-' . esc_attr( $d->status ) . '"><td class="m28-date">' . $date_display . '</td><td class="m28-menu">' . $menu_html . '</td><td class="m28-status">' . $status_label . '</td><td class="m28-action">' . $action_html . '</td></tr>';
            }
            echo '</tbody></table></div>';
        }
        echo '</div></div></div>';

        // Inline styles and JS (kept for simplicity)
        ?>
        <style>
        .m28-manage-wrap { max-width:100%; margin: 0 0 40px; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif; color: #222; }
        .m28-manage-title { font-size: 28px; margin: 16px 0 6px; }
        .m28-manage-subtitle { color: #666; margin-bottom: 18px; }
        .m28-card { background: #fff; border: 1px solid #e6e6e6; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.02); overflow: hidden; }
        .m28-card-body { padding: 18px; }
        .m28-table-responsive { overflow-x: auto; }
        .m28-table { width: 100%; border-collapse: collapse; min-width: 720px; }
        .m28-table thead th { background:#f9fafb; text-align:left; padding:12px 14px; font-weight:600; border-bottom:1px solid #eee; }
        .m28-table tbody td { padding:12px 14px; border-bottom:1px solid #f0f0f0; vertical-align:top; }
        .m28-date { font-weight:600; color:#111; white-space:nowrap; width:170px; }
        .m28-menu { color:#333; max-width:520px; }
        .m28-menu-list { margin:0; padding-left:18px; }
        .m28-menu-list li { margin:4px 0; }
        .m28-badge { display:inline-block; padding:6px 10px; border-radius:12px; font-size:13px; font-weight:600; text-transform:none; }
        .m28-badge-pending { background:#fff4e5; color:#b35b00; border:1px solid #ffe3b8; }
        .m28-badge-delivered { background:#e6ffed; color:#08660d; border:1px solid #c6f0cf; }
        .m28-badge-skipped { background:#ffecec; color:#a30000; border:1px solid #ffcdcd; }
        .m28-btn { display:inline-flex; align-items:center; gap:8px; padding:8px 12px; border-radius:8px; border:1px solid #d0d0d0; background:#fff; cursor:pointer; font-weight:600; }
        .m28-row-pending:hover { background:#fbfbfb; }
        .m28-row-delivered { opacity:0.95; }
        .m28-row-skipped { background:#fff7f7; }
        @media (max-width:720px) { .m28-manage-wrap { padding: 10px; } .m28-table { min-width:600px; } .m28-date { width:140px; } }
        </style>
        <script>
        (function(){
            function ajaxAction(action, dateId, btn) {
                var data = new URLSearchParams();
                data.append('action', action);
                data.append('date_id', dateId);
                data.append('nonce', '<?php echo wp_create_nonce( M28_FINAL_NONCE ); ?>');
                btn.disabled = true;
                var orig = btn.innerHTML;
                btn.innerHTML = 'Processing...';
                fetch('<?php echo admin_url("admin-ajax.php"); ?>', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
                    body: data.toString(),
                    credentials: 'same-origin'
                }).then(function(resp){ return resp.json(); }).then(function(json){
                    if ( json.success ) { location.reload(); } else { alert(json.data || 'Error'); btn.disabled=false; btn.innerHTML=orig; }
                }).catch(function(err){ console.error(err); alert('Request failed'); btn.disabled=false; btn.innerHTML=orig; });
            }
            document.addEventListener('click', function(e){
                if ( e.target && e.target.closest('.m28-btn-skip') ) {
                    var btn = e.target.closest('.m28-btn-skip'); if ( ! confirm('Skip delivery for this date? This will extend your plan by one day.') ) return;
                    ajaxAction('m28_final_skip_date', btn.getAttribute('data-date-id'), btn);
                }
                if ( e.target && e.target.closest('.m28-btn-revert') ) {
                    var btn = e.target.closest('.m28-btn-revert'); if ( ! confirm('Remove skip for this date?') ) return;
                    ajaxAction('m28_final_remove_skip', btn.getAttribute('data-date-id'), btn);
                }
            });
        })();
        </script>
        <?php
    }

    // AJAX endpoints
    add_action( 'wp_ajax_m28_final_skip_date', 'm28_final_ajax_skip_date' );
    function m28_final_ajax_skip_date() {
        check_ajax_referer( M28_FINAL_NONCE, 'nonce' );
        if ( ! is_user_logged_in() ) wp_send_json_error( 'Not logged in' );
        $user_id = get_current_user_id();
        $date_id = isset($_POST['date_id']) ? intval($_POST['date_id']) : 0;
        if ( ! $date_id ) wp_send_json_error( 'Missing date id' );
        global $wpdb;
        $table_dates = $wpdb->prefix . 'm28_variable_item_dates';
        $table_items = $wpdb->prefix . 'm28_orders_variable_items';
        $row = $wpdb->get_row( $wpdb->prepare( "SELECT d.*, v.user_id FROM $table_dates d JOIN $table_items v ON d.variable_item_id = v.id WHERE d.id = %d", $date_id ) );
        if ( ! $row ) wp_send_json_error( 'Invalid' );
        if ( intval( $row->user_id ) !== $user_id ) wp_send_json_error( 'Not authorized' );
        if ( $row->status !== 'pending' ) wp_send_json_error( 'Only pending dates can be skipped' );
        $tomorrow = date_i18n( 'Y-m-d', strtotime( '+1 day' ) );
        if ( strtotime( $row->delivery_date ) < strtotime( $tomorrow ) ) wp_send_json_error( 'Cannot skip today or past dates' );
        $updated = $wpdb->update( $table_dates, array('status'=>'skipped'), array('id'=>$date_id), array('%s'), array('%d') );
        if ( $updated === false ) wp_send_json_error( 'DB error' );
        $last = $wpdb->get_row( $wpdb->prepare( "SELECT delivery_date FROM $table_dates WHERE variable_item_id = %d ORDER BY delivery_date DESC LIMIT 1", $row->variable_item_id ) );
        $new_date = date_i18n( 'Y-m-d', strtotime( $last->delivery_date . ' +1 day' ) );
        $inserted = $wpdb->insert( $table_dates, array('variable_item_id' => $row->variable_item_id, 'delivery_date' => $new_date, 'menu_key'=>$new_date, 'status'=>'pending'), array('%d','%s','%s','%s') );
        if ( $inserted === false ) wp_send_json_error( 'DB insert error' );
        wp_send_json_success( array('new_date'=>$new_date) );
    }

    add_action( 'wp_ajax_m28_final_remove_skip', 'm28_final_ajax_remove_skip' );
    function m28_final_ajax_remove_skip() {
        check_ajax_referer( M28_FINAL_NONCE, 'nonce' );
        if ( ! is_user_logged_in() ) wp_send_json_error( 'Not logged in' );
        $user_id = get_current_user_id();
        $date_id = isset($_POST['date_id']) ? intval($_POST['date_id']) : 0;
        if ( ! $date_id ) wp_send_json_error( 'Missing date id' );
        global $wpdb;
        $table_dates = $wpdb->prefix . 'm28_variable_item_dates';
        $table_items = $wpdb->prefix . 'm28_orders_variable_items';
        $row = $wpdb->get_row( $wpdb->prepare( "SELECT d.*, v.user_id FROM $table_dates d JOIN $table_items v ON d.variable_item_id = v.id WHERE d.id = %d", $date_id ) );
        if ( ! $row ) wp_send_json_error( 'Invalid' );
        if ( intval( $row->user_id ) !== $user_id ) wp_send_json_error( 'Not authorized' );
        if ( $row->status !== 'skipped' ) wp_send_json_error( 'Only skipped dates can be reverted' );
        $today = date_i18n( 'Y-m-d' );
        if ( strtotime( $row->delivery_date ) <= strtotime( $today ) ) wp_send_json_error( 'Cannot remove skip for today or past deliveries' );
        $last = $wpdb->get_row( $wpdb->prepare( "SELECT id, delivery_date FROM $table_dates WHERE variable_item_id = %d ORDER BY delivery_date DESC LIMIT 1", $row->variable_item_id ) );
        if ( ! $last ) wp_send_json_error( 'No appended date found' );
        if ( strtotime( $last->delivery_date ) <= strtotime( $row->delivery_date ) ) wp_send_json_error( 'No appended date to remove' );
        $deleted = $wpdb->delete( $table_dates, array('id' => $last->id), array('%d') );
        if ( $deleted === false ) wp_send_json_error( 'DB delete error' );
        $updated = $wpdb->update( $table_dates, array('status'=>'pending'), array('id'=>$date_id), array('%s'), array('%d') );
        if ( $updated === false ) wp_send_json_error( 'DB update error' );
        wp_send_json_success();
    }

    // Robust menu lookup function integrated with Meals28 master cycles
    function m28_final_get_menu_html_for_date( $date, $product_id = 0 ) {
        // Normalize date to Y-m-d
        $date_str = date_i18n( 'Y-m-d', strtotime( $date ) );

        // Map product IDs to meal types used by Meals28 menu plugin
        $meal = '';
        switch ( (int) $product_id ) {
            case 91:
                $meal = 'breakfast';
                break;
            case 300:
                $meal = 'lunch';
                break;
            case 306:
                $meal = 'dinner';
                break;
        }

        // If we know the meal and the menu plugin is active, fetch from master cycle
        if ( $meal && function_exists( 'm28_all_get_master' ) && function_exists( 'm28_all_cycle_index_for_date' ) ) {
            $master = m28_all_get_master();
            if ( isset( $master[ $meal ] ) && is_array( $master[ $meal ] ) ) {
                // Which day of cycle is this date?
                $index = m28_all_cycle_index_for_date( $date_str, $meal );
                $idx   = max( 1, min( 28, (int) $index ) ) - 1;

                $row = $master[ $meal ][ $idx ] ?? null;

                if ( $row && ! empty( $row['title'] ) ) {
                    $title       = $row['title'] ?? '';
                    $description = $row['description'] ?? '';
                    $veg         = isset( $row['veg'] ) ? (int) $row['veg'] : 1;
                    $allergens   = $row['allergens'] ?? '';

                    $html  = '<div class="m28-menu-text"><strong>' . esc_html( $title ) . '</strong>';
                    if ( $description !== '' ) {
                        $html .= '<div class="m28-menu-desc">' . esc_html( $description ) . '</div>';
                    }

                    $meta_bits = array();
                    $meta_bits[] = $veg ? 'Veg' : 'Non-Veg';
                    if ( $allergens !== '' ) {
                        $meta_bits[] = 'Allergens: ' . $allergens;
                    }
                    if ( ! empty( $meta_bits ) ) {
                        $html .= '<div class="m28-menu-meta">' . esc_html( implode( ' · ', $meta_bits ) ) . '</div>';
                    }

                    $html .= '</div>';

                    return $html;
                }
            }
        }

        // If menu plugin not available or no data found, fall back to empty cell
        return '';
    }

    function m28_final_menu_to_html( $menu ) {
        if ( is_array( $menu ) ) {
            $items = array_map( 'esc_html', $menu );
            return '<ul class="m28-menu-list"><li>' . implode('</li><li>', $items) . '</li></ul>';
        } else {
            return '<div class="m28-menu-text">' . esc_html( $menu ) . '</div>';
        }
    }

    // Embedded manage routing: detect query param and render
    add_action( 'woocommerce_account_variable-products_endpoint', 'm28_final_account_endpoint_wrapper' );
    function m28_final_account_endpoint_wrapper() {
        // call main endpoint
        m28_final_account_endpoint();
        // if query requests manage, render inline
        if ( isset($_GET['m28_item']) && isset($_GET['action']) && $_GET['action'] === 'manage' ) {
            $item_id = intval( $_GET['m28_item'] );
            echo '<div style="margin-top:18px;">';
            m28_final_render_manage_page( $item_id );
            echo '</div>';
        }
    }
} // end setup
