<?php

/**
 * @package QuickStockForWooCommerce
 * @license GPL-2.0-or-later (https://www.gnu.org/licenses/gpl-2.0.html)
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
class QSFW_Renderer {
    private static $term_cache = array();

    /**
     * Gibt ein SVG-Icon aus der internen Whitelist direkt aus.
     *
     * Bewusst ein switch mit je einem Literal-echo statt eines Arrays: nur so
     * erkennt der Escaping-Sniff die Ausgabe als unbedenklich, und viewBox
     * behaelt seine Grossschreibung (wp_kses() wuerde daraus ab WP 6.2
     * viewbox machen und das SVG damit brechen).
     *
     * @param string $name Icon-Schluessel.
     */
    public static function echo_icon( $name ) {
        switch ( $name ) {
            case 'box':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10m0-10l8-4"/></svg></span>';
                break;
            case 'cart':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13 5.4 5M7 13l-2.3 2.3A1 1 0 0 0 5.4 17H17"/><circle cx="9" cy="20" r="1"/><circle cx="18" cy="20" r="1"/></svg></span>';
                break;
            case 'clipboard':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2"/><path d="M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2z"/><path d="m9 14 2 2 4-4"/></svg></span>';
                break;
            case 'history':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 3v5h5"/><path d="M3.05 13A9 9 0 1 0 6 5.3L3 8"/><path d="M12 7v5l4 2"/></svg></span>';
                break;
            case 'gear':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span>';
                break;
            case 'crown':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 16 3 5l5.5 5L12 4l3.5 6L21 5l-2 11H5zm0 3h14"/></svg></span>';
                break;
            case 'sliders':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></svg></span>';
                break;
            case 'columns':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M9 4v16M15 4v16"/></svg></span>';
                break;
            case 'truck':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M10 17h4V5H2v12h3"/><path d="M14 8h4l4 4v5h-3"/><circle cx="7.5" cy="17.5" r="2.5"/><circle cx="16.5" cy="17.5" r="2.5"/></svg></span>';
                break;
            case 'tag':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20.6 13.1 13 20.7a2 2 0 0 1-2.8 0L3 13.5V3h10.5l7.1 7.1a2 2 0 0 1 0 3z"/><circle cx="7.5" cy="7.5" r="1.5"/></svg></span>';
                break;
            case 'bookmark':
                echo '<span class="qsfw-svg-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg></span>';
                break;
        }
    }

    /* ===================================================================
     * FREE/PRO: Einheitliche „💎 Pro"-Hinweis-Komponente (Phase 4)
     * Einziger Renderer für alle Pro-Nudges. Server-Guards (class-ajax.php
     * via qsfw_can_use()) sind die Wahrheit; diese Helfer sind nur UI-Komfort.
     * Sobald Freemius angebunden ist, liefert nur `pro_upgrade_url()` die
     * Checkout-URL – alle Aufrufer bleiben unverändert.
     * =================================================================== */
    /**
     * Upgrade-/Checkout-URL für Pro. Vorerst leer (Freemius noch nicht
     * angebunden); später füllt der Filter `qsfw_upgrade_url` die echte URL.
     */
    public static function pro_upgrade_url() {
        return (string) apply_filters( 'qsfw_upgrade_url', '' );
    }

    /**
     * Dezentes „💎 Pro"-Badge (inline). Einheitliche Komponente für alle
     * Pro-Hinweise neben Überschriften/Labels.
     *
     * @param string|null $text Badge-Text; null = „Pro".
     */
    public static function pro_badge( $text = null ) {
        if ( $text === null ) {
            $text = __( 'Pro', 'quickstock-for-woocommerce' );
        }
        return '<span class="qsfw-pro-hint" style="display:inline-flex;align-items:center;gap:5px;' . 'padding:3px 10px;border-radius:10px;font-size:12px;font-weight:600;' . 'color:#6b4d00;background:#fff3cd;border:1px solid #f5d77e;vertical-align:middle;">' . '<span aria-hidden="true">💎</span>' . esc_html( $text ) . '</span>';
    }

    /**
     * Kleines 💎-Icon als Suffix für Tabs/Labels gesperrter Pro-Bereiche.
     * Beginnt mit einem Leerzeichen, damit es sich direkt anhängen lässt.
     */
    public static function pro_tab_marker() {
        return ' <span class="qsfw-pro-marker" title="' . esc_attr__( 'Pro feature', 'quickstock-for-woocommerce' ) . '" aria-hidden="true">💎</span>';
    }

    /**
     * Einheitliches Upsell-Panel für komplett gesperrte Pro-Bereiche (PO-Tab,
     * Lieferanten-Subtab). Zeigt – sobald `pro_upgrade_url()` eine URL liefert –
     * zusätzlich einen Upgrade-Button.
     *
     * @param string $icon  Emoji-Icon (z. B. „📥").
     * @param string $title Überschrift (bereits übersetzt).
     * @param string $desc  Beschreibung (bereits übersetzt).
     */
    public static function pro_upsell_panel( $icon, $title, $desc ) {
        $url = self::pro_upgrade_url();
        $html = '<div class="qsfw-pro-upsell" style="max-width:560px;margin:48px auto;text-align:center;padding:36px 32px;border:1px solid #e0e0e0;border-radius:12px;background:#fff;">';
        $html .= '<div style="font-size:42px;line-height:1;">' . esc_html( $icon ) . '</div>';
        $html .= '<h2 style="margin:16px 0 10px;">' . esc_html( $title ) . ' ' . self::pro_badge() . '</h2>';
        $html .= '<p style="color:#646970;font-size:14px;line-height:1.6;margin:0 auto;max-width:42em;">' . esc_html( $desc ) . '</p>';
        if ( $url !== '' ) {
            $html .= '<p style="margin-top:22px;"><a class="button button-primary" href="' . esc_url( $url ) . '" target="_blank" rel="noopener">' . esc_html__( 'Upgrade to Pro', 'quickstock-for-woocommerce' ) . '</a></p>';
        }
        $html .= '</div>';
        return $html;
    }

    /**
     * echo-Varianten der drei Pro-Nudges. Gleiche Komponente, nur direkte
     * Ausgabe – noetig, weil der Escaping-Sniff jede Funktion im echo-Ausdruck
     * bemaengelt, unabhaengig davon, was sie intern escapt.
     */
    public static function echo_pro_badge( $text = null ) {
        if ( $text === null ) {
            $text = __( 'Pro', 'quickstock-for-woocommerce' );
        }
        echo '<span class="qsfw-pro-hint" style="display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:10px;font-size:12px;font-weight:600;color:#6b4d00;background:#fff3cd;border:1px solid #f5d77e;vertical-align:middle;">';
        echo '<span aria-hidden="true">💎</span>';
        echo esc_html( $text );
        echo '</span>';
    }

    public static function echo_pro_tab_marker() {
        echo ' <span class="qsfw-pro-marker" title="' . esc_attr__( 'Pro feature', 'quickstock-for-woocommerce' ) . '" aria-hidden="true">💎</span>';
    }

    public static function echo_pro_upsell_panel( $icon, $title, $desc ) {
        $url = self::pro_upgrade_url();
        echo '<div class="qsfw-pro-upsell" style="max-width:560px;margin:48px auto;text-align:center;padding:36px 32px;border:1px solid #e0e0e0;border-radius:12px;background:#fff;">';
        echo '<div style="font-size:42px;line-height:1;">' . esc_html( $icon ) . '</div>';
        echo '<h2 style="margin:16px 0 10px;">' . esc_html( $title ) . ' ';
        self::echo_pro_badge();
        echo '</h2>';
        echo '<p style="color:#646970;font-size:14px;line-height:1.6;margin:0 auto;max-width:42em;">' . esc_html( $desc ) . '</p>';
        if ( $url !== '' ) {
            echo '<p style="margin-top:22px;"><a class="button button-primary" href="' . esc_url( $url ) . '" target="_blank" rel="noopener">';
            echo esc_html__( 'Upgrade to Pro', 'quickstock-for-woocommerce' );
            echo '</a></p>';
        }
        echo '</div>';
    }

    public static function render_term_select(
        $product_id,
        $taxonomy,
        $current_id,
        $type
    ) {
        ob_start();
        self::echo_term_select(
            $product_id,
            $taxonomy,
            $current_id,
            $type
        );
        return ob_get_clean();
    }

    /**
     * Wie render_term_select(), gibt das <select> aber direkt feldweise escaped
     * aus, statt es als String zurueckzugeben.
     */
    public static function echo_term_select(
        $product_id,
        $taxonomy,
        $current_id,
        $type
    ) {
        if ( !isset( self::$term_cache[$taxonomy] ) ) {
            $terms = get_terms( array(
                'taxonomy'   => $taxonomy,
                'hide_empty' => false,
            ) );
            self::$term_cache[$taxonomy] = ( is_wp_error( $terms ) || !is_array( $terms ) ? array() : $terms );
        }
        echo '<select class="edit-input select-input" data-id="' . (int) $product_id . '" data-type="' . esc_attr( $type ) . '">';
        echo '<option value="0">— —</option>';
        foreach ( self::$term_cache[$taxonomy] as $term ) {
            echo '<option value="' . (int) $term->term_id . '" ' . selected( $current_id, $term->term_id, false ) . '>' . esc_html( html_entity_decode( $term->name, ENT_QUOTES, 'UTF-8' ) ) . '</option>';
        }
        echo '</select>';
    }

    /**
     * @param object      $p        Zeilenobjekt aus QSFW_Data.
     * @param array       $checks   "Erledigt"-Markierungen.
     * @param array|null  $columns  Aktive Spalten.
     * @param string      $row_kind 'normal' | 'parent' (Gruppen-Kopf) | 'child' (Variation).
     */
    public static function render_row(
        $p,
        $checks,
        $columns = null,
        $row_kind = 'normal'
    ) {
        ob_start();
        self::echo_row(
            $p,
            $checks,
            $columns,
            $row_kind
        );
        return ob_get_clean();
    }

    /**
     * Wie render_row(), gibt die Tabellenzeile aber direkt feldweise escaped aus,
     * statt sie als String zurueckzugeben. render_row() ist nur noch eine
     * ob_start()-Huelle darum (fuer den AJAX-Pfad in class-ajax.php).
     *
     * @param object      $p        Zeilenobjekt aus QSFW_Data.
     * @param array       $checks   "Erledigt"-Markierungen.
     * @param array|null  $columns  Aktive Spalten.
     * @param string      $row_kind 'normal' | 'parent' (Gruppen-Kopf) | 'child' (Variation).
     */
    public static function echo_row(
        $p,
        $checks,
        $columns = null,
        $row_kind = 'normal'
    ) {
        if ( $columns === null ) {
            $columns = QSFW_Columns::get_active();
        }
        $is_c = isset( $checks[$p->ID] );
        $vk = ( !empty( $p->sale_price ) ? (float) $p->sale_price : (float) $p->regular_price );
        $manage_stock = isset( $p->manage_stock ) && $p->manage_stock === 'yes';
        $stock_qty = ( $manage_stock ? (int) $p->stock_qty : null );
        $s_class = '';
        if ( $manage_stock ) {
            // Nachbestellgrenze: Produkt-Override > WC-Standard (via class-data.php)
            $threshold = (int) $p->threshold;
            if ( $stock_qty < $threshold ) {
                $s_class = 'stock-critical';
            } elseif ( $stock_qty === $threshold ) {
                $s_class = 'stock-warning';
            } else {
                $s_class = 'stock-ok';
            }
        }
        $is_variation = ( isset( $p->post_type ) ? $p->post_type === 'product_variation' : ($po = get_post( $p->ID )) && $po->post_type === 'product_variation' );
        // Gruppierungs-Markup: aufklappbarer Eltern-Kopf bzw. versteckte Variations-Zeile.
        $tr_classes = array();
        // „Erledigt"-Ausgrauen nur im Nachbestell-Modus: bei „Alle Produkte"
        // lassen sich keine Haken setzen, also sollen abgehakte Produkte dort
        // auch nicht ausgegraut erscheinen.
        if ( $is_c && QSFW_Columns::get_mode() === 'reorder' ) {
            $tr_classes[] = 'stock-done';
        }
        if ( $row_kind === 'parent' ) {
            $tr_classes[] = 'qsfw-parent-row';
        } elseif ( $row_kind === 'child' ) {
            $tr_classes[] = 'qsfw-variation-row';
            $tr_classes[] = 'qsfw-collapsed';
        }
        $child_count = ( $row_kind === 'parent' && isset( $p->qsfw_children ) ? count( $p->qsfw_children ) : 0 );
        echo '<tr class="' . esc_attr( trim( implode( ' ', $tr_classes ) ) ) . '"';
        if ( $row_kind === 'parent' ) {
            echo ' data-product-id="' . (int) $p->ID . '" data-child-count="' . (int) $child_count . '"';
        } elseif ( $row_kind === 'child' ) {
            echo ' data-parent="' . (( isset( $p->post_parent ) ? (int) $p->post_parent : 0 )) . '" hidden';
        }
        echo '>';
        foreach ( $columns as $key => $cfg ) {
            switch ( $key ) {
                case 'bulk_select':
                    echo '<td class="hb-bulk-cell"><input type="checkbox" class="hb-bulk-check" data-id="' . (int) $p->ID . '" data-sku="' . esc_attr( $p->sku ) . '"></td>';
                    break;
                case 'check':
                    echo '<td><input type="checkbox" class="stock-check" data-id="' . (int) $p->ID . '" ' . checked( $is_c, true, false ) . '></td>';
                    break;
                case 'image':
                    $thumb_id = (int) get_post_thumbnail_id( $p->ID );
                    // Variationen ohne eigenes Bild: Bild des Elternprodukts anzeigen
                    // (rein visuell – das Klick-Ziel bleibt die Variation selbst).
                    $inherited = false;
                    if ( !$thumb_id && $is_variation && !empty( $p->post_parent ) ) {
                        $thumb_id = (int) get_post_thumbnail_id( (int) $p->post_parent );
                        $inherited = $thumb_id > 0;
                    }
                    $img = ( $thumb_id ? wp_get_attachment_image_url( $thumb_id, array(40, 40) ) : '' );
                    echo '<td class="col-image"><span class="hb-img-edit" data-id="' . (int) $p->ID . '" title="' . (( $inherited ? esc_attr__( 'Parent product image (variation has none) – click to set a variation image', 'quickstock-for-woocommerce' ) : esc_attr__( 'Change main image', 'quickstock-for-woocommerce' ) )) . '">';
                    if ( $img ) {
                        echo '<img src="' . esc_url( $img ) . '"' . (( $inherited ? ' class="qsfw-inherited-img"' : '' )) . (( QSFW_Settings_Page::get_general_setting( 'lazy_load_images', 1 ) ? ' loading="lazy"' : '' )) . '>';
                    } else {
                        echo '<span class="hb-img-add">+</span>';
                    }
                    echo '</span></td>';
                    break;
                case 'sku':
                    echo '<td><input type="text" class="edit-input sku-input" data-id="' . (int) $p->ID . '" data-type="sku" value="' . esc_attr( $p->sku ) . '" /><br><span class="action-icon label-print-btn" data-sku="' . esc_attr( $p->sku ) . '" data-title="' . esc_attr( $p->post_title ) . '" data-price="' . esc_attr( $vk ) . '" data-regular="' . esc_attr( $p->regular_price ) . '" data-sale="' . esc_attr( $p->sale_price ) . '" title="' . esc_attr__( 'Print label', 'quickstock-for-woocommerce' ) . '">🏷️</span></td>';
                    break;
                case 'title':
                    if ( $is_variation ) {
                        // Variationen haben keinen eigenen Edit-Link (get_edit_post_link()
                        // liefert für 'product_variation' leer) → auf das Elternprodukt verlinken.
                        $parent_id = ( isset( $p->post_parent ) ? (int) $p->post_parent : 0 );
                        $edit_parent = ( $parent_id ? get_edit_post_link( $parent_id ) : '' );
                        echo '<td class="col-title"><span title="' . esc_attr__( 'Variations cannot be renamed here', 'quickstock-for-woocommerce' ) . '">' . esc_html( $p->post_title ) . '</span> <span class="copy-btn action-icon" data-title="' . esc_attr( $p->post_title ) . '">📋</span> <a href="' . esc_url( $edit_parent ) . '" class="action-icon" target="_blank" title="' . esc_attr__( 'Edit parent product', 'quickstock-for-woocommerce' ) . '">✎</a></td>';
                    } else {
                        echo '<td class="col-title">';
                        if ( $row_kind === 'parent' ) {
                            /* translators: %d is the number of variations under this product */
                            $toggle_title = sprintf( _n(
                                'Show / hide %d variation',
                                'Show / hide %d variations',
                                $child_count,
                                'quickstock-for-woocommerce'
                            ), $child_count );
                            /* translators: %d is the number of variations under this product (shown on the toggle button) */
                            $toggle_label = sprintf( _n(
                                '%d variation',
                                '%d variations',
                                $child_count,
                                'quickstock-for-woocommerce'
                            ), $child_count );
                            echo '<button type="button" class="qsfw-var-toggle" aria-expanded="false" title="' . esc_attr( $toggle_title ) . '"><span class="qsfw-var-arrow" aria-hidden="true">▶</span><span class="qsfw-var-count">' . esc_html( $toggle_label ) . '</span></button> ';
                        }
                        echo '<input type="text" class="edit-input title-input" data-id="' . (int) $p->ID . '" data-type="title" value="' . esc_attr( $p->post_title ) . '" /> <span class="copy-btn action-icon" data-title="' . esc_attr( $p->post_title ) . '">📋</span> <a href="' . esc_url( get_edit_post_link( $p->ID ) ) . '" class="action-icon" target="_blank">✎</a></td>';
                    }
                    break;
                case 'price_reg':
                    echo '<td><input type="text" class="edit-input" data-calc="money" data-id="' . (int) $p->ID . '" data-type="price" value="' . esc_attr( $p->regular_price ) . '"></td>';
                    break;
                case 'price_sale':
                    echo '<td><input type="text" class="edit-input" data-calc="money" data-id="' . (int) $p->ID . '" data-type="sale" value="' . esc_attr( $p->sale_price ) . '"></td>';
                    break;
                case 'sale_from':
                    $val = ( isset( $p->sale_from ) && $p->sale_from ? gmdate( 'Y-m-d', (int) $p->sale_from ) : '' );
                    echo '<td><input type="date" class="edit-input date-input" data-id="' . (int) $p->ID . '" data-type="sale_from" value="' . esc_attr( $val ) . '"></td>';
                    break;
                case 'sale_to':
                    $val = ( isset( $p->sale_to ) && $p->sale_to ? gmdate( 'Y-m-d', (int) $p->sale_to ) : '' );
                    echo '<td><input type="date" class="edit-input date-input" data-id="' . (int) $p->ID . '" data-type="sale_to" value="' . esc_attr( $val ) . '"></td>';
                    break;
                case 'stock':
                    if ( $row_kind === 'parent' && !empty( $p->qsfw_has_agg ) ) {
                        // Bestand wird auf Varianten-Ebene verwaltet → Summe in gesperrter
                        // Box anzeigen (sieht aus wie ein gesperrtes einfaches Produkt).
                        $agg = ( $p->qsfw_agg_stock === null ? '—' : (string) (int) $p->qsfw_agg_stock );
                        echo '<td><input type="text" class="edit-input stock-disabled qsfw-agg-stock" value="' . esc_attr( $agg ) . '" disabled title="' . esc_attr__( 'Sum of variation stock — edit each variation below', 'quickstock-for-woocommerce' ) . '"></td>';
                        break;
                    }
                    if ( $manage_stock ) {
                        echo '<td><div class="num-spinner"><input type="text" class="edit-input ' . esc_attr( $s_class ) . '" data-calc="int" data-id="' . (int) $p->ID . '" data-type="stock" value="' . (int) $stock_qty . '"><div class="ns-btns"><button type="button" class="ns-btn ns-up" tabindex="-1">▲</button><button type="button" class="ns-btn ns-down" tabindex="-1">▼</button></div></div></td>';
                    } else {
                        echo '<td><input type="text" class="edit-input stock-disabled" data-id="' . (int) $p->ID . '" data-type="stock" value="" placeholder="—" disabled title="' . esc_attr__( 'Stock management disabled', 'quickstock-for-woocommerce' ) . '"></td>';
                    }
                    break;
                case 'limit':
                    echo '<td><div class="num-spinner"><input type="text" class="edit-input" data-calc="int" data-id="' . (int) $p->ID . '" data-type="limit" value="' . (int) $p->threshold . '"><div class="ns-btns"><button type="button" class="ns-btn ns-up" tabindex="-1">▲</button><button type="button" class="ns-btn ns-down" tabindex="-1">▼</button></div></div></td>';
                    break;
                case 'restock_target':
                    $rt_val = ( isset( $p->restock_target ) && $p->restock_target !== '' ? (int) $p->restock_target : '' );
                    echo '<td><div class="num-spinner"><input type="text" class="edit-input" data-calc="int" data-id="' . (int) $p->ID . '" data-type="restock_target" value="' . esc_attr( $rt_val ) . '"><div class="ns-btns"><button type="button" class="ns-btn ns-up" tabindex="-1">▲</button><button type="button" class="ns-btn ns-down" tabindex="-1">▼</button></div></div></td>';
                    break;
                case 'order_qty':
                    $oq_val = ( isset( $p->order_qty ) && $p->order_qty !== '' ? (int) $p->order_qty : '' );
                    // Vorschlag aus Zielbestand − aktuellem Bestand (nur als Platzhalter,
                    // wird erst beim Klick auf „Mengen berechnen" oder manuell gespeichert).
                    $oq_target = ( isset( $p->restock_target ) && $p->restock_target !== '' ? (int) $p->restock_target : (int) QSFW_Settings_Page::get_general_setting( 'default_restock_target', 0 ) );
                    $oq_cur = ( $stock_qty === null ? 0 : (int) $stock_qty );
                    $oq_sugg = ( $oq_target > 0 ? max( 0, $oq_target - $oq_cur ) : 0 );
                    echo '<td><div class="num-spinner"><input type="text" class="edit-input qsfw-order-qty" data-calc="int" data-id="' . (int) $p->ID . '" data-type="order_qty" data-target="' . esc_attr( $oq_target ) . '" value="' . esc_attr( $oq_val ) . '"' . (( $oq_val === '' && $oq_sugg > 0 ? ' placeholder="' . esc_attr( $oq_sugg ) . '"' : '' )) . '><div class="ns-btns"><button type="button" class="ns-btn ns-up" tabindex="-1">▲</button><button type="button" class="ns-btn ns-down" tabindex="-1">▼</button></div></div></td>';
                    break;
                case 'manage_stock':
                    echo '<td style="text-align:center;"><input type="checkbox" class="manage-stock-toggle" data-id="' . (int) $p->ID . '" data-type="manage_stock" ' . (( $manage_stock ? 'checked' : '' )) . '></td>';
                    break;
                case 'no_label':
                    break;
                case 'stock_status':
                    $ss = ( isset( $p->stock_status ) && $p->stock_status ? $p->stock_status : 'instock' );
                    $opts = array(
                        'instock'     => __( 'In stock', 'quickstock-for-woocommerce' ),
                        'outofstock'  => __( 'Out of stock', 'quickstock-for-woocommerce' ),
                        'onbackorder' => __( 'On backorder', 'quickstock-for-woocommerce' ),
                    );
                    echo '<td><select class="edit-input select-input" data-id="' . (int) $p->ID . '" data-type="stock_status">';
                    foreach ( $opts as $val => $lbl ) {
                        echo '<option value="' . esc_attr( $val ) . '" ' . selected( $ss, $val, false ) . '>' . esc_html( $lbl ) . '</option>';
                    }
                    echo '</select></td>';
                    break;
                case 'backorders':
                    $bo = ( isset( $p->backorders ) && $p->backorders ? $p->backorders : 'no' );
                    $opts = array(
                        'no'     => __( 'Do not allow', 'quickstock-for-woocommerce' ),
                        'notify' => __( 'Allow, but notify customer', 'quickstock-for-woocommerce' ),
                        'yes'    => __( 'Allow', 'quickstock-for-woocommerce' ),
                    );
                    echo '<td><select class="edit-input select-input" data-id="' . (int) $p->ID . '" data-type="backorders">';
                    foreach ( $opts as $val => $lbl ) {
                        echo '<option value="' . esc_attr( $val ) . '" ' . selected( $bo, $val, false ) . '>' . esc_html( $lbl ) . '</option>';
                    }
                    echo '</select></td>';
                    break;
                case 'shipping_class':
                    $cur = ( isset( $p->shipping_class_id ) ? (int) $p->shipping_class_id : 0 );
                    echo '<td>';
                    self::echo_term_select(
                        $p->ID,
                        'product_shipping_class',
                        $cur,
                        'shipping_class'
                    );
                    echo '</td>';
                    break;
                case 'product_cat':
                    $cats = QSFW_Data::get_product_categories( $p->ID );
                    echo '<td><div class="cat-display" title="' . esc_attr( $cats ) . '">' . esc_html( $cats ) . '</div></td>';
                    break;
                case 'permalink':
                    $slug = ( isset( $p->post_name ) ? $p->post_name : '' );
                    $url = get_permalink( $p->ID );
                    echo '<td><input type="text" class="edit-input permalink-input" data-id="' . (int) $p->ID . '" data-type="permalink" value="' . esc_attr( $slug ) . '" />' . (( $url ? ' <a href="' . esc_url( $url ) . '" target="_blank" class="action-icon" title="' . esc_attr__( 'View in shop', 'quickstock-for-woocommerce' ) . '">🔗</a>' : '' )) . '</td>';
                    break;
                case 'post_status':
                    $ps = ( isset( $p->post_status_val ) ? $p->post_status_val : 'publish' );
                    $opts = array(
                        'publish' => __( 'Published', 'quickstock-for-woocommerce' ),
                        'draft'   => __( 'Draft', 'quickstock-for-woocommerce' ),
                        'private' => __( 'Private', 'quickstock-for-woocommerce' ),
                        'pending' => __( 'Pending review', 'quickstock-for-woocommerce' ),
                    );
                    echo '<td><select class="edit-input select-input" data-id="' . (int) $p->ID . '" data-type="post_status">';
                    foreach ( $opts as $val => $lbl ) {
                        echo '<option value="' . esc_attr( $val ) . '" ' . selected( $ps, $val, false ) . '>' . esc_html( $lbl ) . '</option>';
                    }
                    echo '</select></td>';
                    break;
                case 'global_unique_id':
                    $gid = ( isset( $p->global_unique_id ) ? $p->global_unique_id : '' );
                    echo '<td><input type="text" class="edit-input" data-id="' . (int) $p->ID . '" data-type="global_unique_id" value="' . esc_attr( $gid ) . '" /></td>';
                    break;
                case 'supplier':
                    break;
                case 'supplier_sku':
                    break;
                case 'cogs':
                    break;
                case 'excerpt':
                    $ex = ( isset( $p->post_excerpt ) ? $p->post_excerpt : '' );
                    echo '<td><textarea class="edit-input textarea-input" data-id="' . (int) $p->ID . '" data-type="excerpt" rows="2">' . esc_textarea( $ex ) . '</textarea></td>';
                    break;
                case 'content':
                    $ct = ( isset( $p->post_content ) ? $p->post_content : '' );
                    $preview = mb_substr( wp_strip_all_tags( $ct ), 0, 80 );
                    echo '<td><div class="content-preview" title="' . esc_attr( wp_strip_all_tags( $ct ) ) . '">' . esc_html( $preview ) . (( mb_strlen( wp_strip_all_tags( $ct ) ) > 80 ? '…' : '' )) . '</div><a href="' . esc_url( get_edit_post_link( $p->ID ) ) . '" class="action-icon" target="_blank" title="' . esc_attr__( 'Edit in WP', 'quickstock-for-woocommerce' ) . '">✎ ' . esc_html__( 'Edit', 'quickstock-for-woocommerce' ) . '</a></td>';
                    break;
                default:
                    break;
            }
        }
        echo '</tr>';
    }

}
