/**
 * AIEO Attribution admin — client-side DataTable for the detail grid.
 *
 * Sortable headers, per-page selector, search, paginator. Thin — fetches
 * a page of rows from `aieo_attribution_rows` on each change and
 * re-renders. Uses jQuery because the rest of DMM already loads it;
 * staying on the same stack keeps the bundle footprint flat.
 */
(function ($) {
    'use strict';

    var __ = ( window.wp && window.wp.i18n && window.wp.i18n.__ ) ? window.wp.i18n.__ : function (s) { return s; };
    var _x = ( window.wp && window.wp.i18n && window.wp.i18n._x ) ? window.wp.i18n._x : function (s) { return s; };
    var _n = ( window.wp && window.wp.i18n && window.wp.i18n._n ) ? window.wp.i18n._n : function (s, p, n) { return n === 1 ? s : p; };
    var _sprintf = ( window.wp && window.wp.i18n && window.wp.i18n.sprintf ) ? window.wp.i18n.sprintf : function (s) { return s; };

    if (!window.aieoAttrAdmin) return;
    var CFG = window.aieoAttrAdmin;

    function esc(s) {
        return String(s == null ? '' : s)
            .replace(/&/g, '&amp;').replace(/</g, '&lt;')
            .replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
    }

    var COL_LABELS = (CFG.i18n && CFG.i18n.columns) || {};
    var COLUMNS = [
        { key: 'status',          label: COL_LABELS.status         || __( 'Status',           'ai-eshop-optimizer' ), sortable: true  },
        { key: 'bought',          label: COL_LABELS.bought         || __( 'Bought / added',   'ai-eshop-optimizer' ), sortable: false, sortKey: 'bought_pid' },
        { key: 'closing_source',  label: COL_LABELS.closingSource  || __( 'Closed via',       'ai-eshop-optimizer' ), sortable: true  },
        { key: 'assist_type',     label: COL_LABELS.assistType     || __( 'Reco type',        'ai-eshop-optimizer' ), sortable: true  },
        { key: 'assist_surface',  label: COL_LABELS.assistSurface  || __( 'Reco surface',     'ai-eshop-optimizer' ), sortable: true  },
        { key: 'assist_position', label: COL_LABELS.assistPosition || __( 'Slot',             'ai-eshop-optimizer' ), sortable: true  },
        { key: 'anchor',          label: COL_LABELS.anchor         || __( 'Shown on / under', 'ai-eshop-optimizer' ), sortable: false, sortKey: 'anchor_pid' },
        { key: 'gap_minutes',     label: COL_LABELS.gap            || __( 'Gap',              'ai-eshop-optimizer' ), sortable: true  },
        { key: 'bought_ts',       label: COL_LABELS.addedAt        || __( 'Added at',         'ai-eshop-optimizer' ), sortable: true  },
    ];

    function renderStatus(r) {
        if (r.status === 'purchased' && r.order_id) {
            var orderHtml = '<a href="' + esc(r.order_url) + '">#' + esc(r.order_id) + '</a>';
            /* translators: %s is the order link */
            var purchased = (CFG.i18n && CFG.i18n.purchased) || __( 'Purchased %s', 'ai-eshop-optimizer' );
            return '<span class="aieo-attr-pill aieo-attr-pill-ok">'
                + purchased.replace('%s', orderHtml)
                + '</span>';
        }
        return '<span class="aieo-attr-pill aieo-attr-pill-warn">'
            + esc((CFG.i18n && CFG.i18n.inCart) || __( 'In cart', 'ai-eshop-optimizer' ))
            + '</span>';
    }

    function renderBought(r) {
        if (!r.bought_pid) return '—';
        var name = r.bought_name || ('#' + r.bought_pid);
        return '<a href="' + esc(r.bought_url) + '">' + esc(name) + '</a>'
            + ' <span style="color:#646970;">#' + r.bought_pid + '</span>';
    }

    function renderAnchor(r) {
        // Product anchor wins (single-product / sidecart-seed surfaces).
        if (r.anchor_pid && r.anchor_name) {
            return '<a href="' + esc(r.anchor_url) + '">' + esc(r.anchor_name) + '</a>'
                + ' <span style="color:#646970;">#' + r.anchor_pid + '</span>';
        }
        // Term anchor — archive surfaces carry the category / brand /
        // tag the shopper was browsing when they saw the recommendation.
        if (r.anchor_term_id && r.anchor_term_name) {
            var taxLabel = '';
            if (r.anchor_term_tax === 'product_cat')   taxLabel = 'Category';
            if (r.anchor_term_tax === 'product_brand') taxLabel = 'Brand';
            if (r.anchor_term_tax === 'product_tag')   taxLabel = 'Tag';
            var nameHtml = r.anchor_term_url
                ? '<a href="' + esc(r.anchor_term_url) + '">' + esc(r.anchor_term_name) + '</a>'
                : esc(r.anchor_term_name);
            return nameHtml
                + (taxLabel
                    ? ' <span style="font-size:11px;color:#646970;">(' + taxLabel + ')</span>'
                    : '');
        }
        return '<span style="color:#646970;">' + esc(r.anchor_fallback || '—') + '</span>';
    }

    function renderSurface(r) {
        return '<code>' + esc(r.assist_surface) + '</code>'
            + '<br><span style="font-size:11px;color:#646970;">' + esc(r.assist_surface_label) + '</span>';
    }

    function renderGap(r) {
        var g = r.gap_minutes | 0;
        if (g < 60) return g + ' min';
        return (g / 60).toFixed(1) + ' h';
    }

    function renderCell(col, r) {
        switch (col.key) {
            case 'status':          return renderStatus(r);
            case 'bought':          return renderBought(r);
            case 'closing_source':  return '<code>' + esc(r.closing_source) + '</code>';
            case 'assist_type':     return esc(r.assist_type);
            case 'assist_surface':  return renderSurface(r);
            case 'assist_position': return r.assist_position > 0
                ? '<span style="display:inline-block;min-width:28px;text-align:center;padding:2px 6px;background:#eef2ff;border-radius:4px;color:#3730a3;font-weight:600;">#' + r.assist_position + '</span>'
                : '<span style="color:#646970;">—</span>';
            case 'anchor':          return renderAnchor(r);
            case 'gap_minutes':     return esc(renderGap(r));
            case 'bought_ts':       return esc(r.bought_ts);
        }
        return '';
    }

    function Table($root) {
        this.$root = $root;
        this.state = {
            days:     parseInt($root.attr('data-days'), 10) || 30,
            page:     1,
            per_page: 25,
            sort:     'bought_ts',
            dir:      'desc',
            search:   '',
            badge:    '', // '' | sale | new | gift | monthly — Phase 8 filter
        };
        this.mount();
        this.load();
    }

    Table.prototype.mount = function () {
        var ph = CFG.i18n.searchPlaceholder || __( 'Search…', 'ai-eshop-optimizer' );
        var badgeLabel = CFG.i18n.badgeLabel  || __( 'Badge', 'ai-eshop-optimizer' );
        var anyLabel   = CFG.i18n.badgeAny    || __( 'Any badge', 'ai-eshop-optimizer' );
        this.$root.html(
            '<div class="aieo-attr-dt-toolbar">'
                + '<input type="search" class="aieo-attr-dt-search" placeholder="' + esc(ph) + '">'
                + '<label style="margin-left:8px;">' + esc(badgeLabel) + ' '
                +   '<select class="aieo-attr-dt-badge">'
                +     '<option value="">' + esc(anyLabel) + '</option>'
                +     '<option value="sale">' + esc( _x( 'SALE', 'sale badge', 'ai-eshop-optimizer' ) ) + '</option>'
                +     '<option value="new">' + esc( _x( 'NEW', 'new badge', 'ai-eshop-optimizer' ) ) + '</option>'
                +     '<option value="gift">' + esc(CFG.i18n.badgeGift    || __( 'Free gift', 'ai-eshop-optimizer' ))     + '</option>'
                +     '<option value="monthly">' + esc(CFG.i18n.badgeMonthly || __( 'Monthly offer', 'ai-eshop-optimizer' )) + '</option>'
                +   '</select>'
                + '</label>'
                + '<div class="spacer"></div>'
                + '<label>' + esc(CFG.i18n.perPage || __( 'Rows per page', 'ai-eshop-optimizer' )) + ' '
                +   '<select class="aieo-attr-dt-perpage">'
                +     '<option value="10">10</option>'
                +     '<option value="25" selected>25</option>'
                +     '<option value="50">50</option>'
                +     '<option value="100">100</option>'
                +     '<option value="200">200</option>'
                +   '</select>'
                + '</label>'
            + '</div>'
            + '<div class="aieo-attr-dt-body"></div>'
            + '<div class="aieo-attr-dt-footer">'
                + '<div class="aieo-attr-dt-summary"></div>'
                + '<div class="aieo-attr-dt-pager"></div>'
            + '</div>'
        );
        var t = this;
        var debounce;
        this.$root.on('input', '.aieo-attr-dt-search', function () {
            clearTimeout(debounce);
            var v = this.value;
            debounce = setTimeout(function () {
                t.state.search = v; t.state.page = 1; t.load();
            }, 250);
        });
        this.$root.on('change', '.aieo-attr-dt-perpage', function () {
            t.state.per_page = parseInt(this.value, 10) || 25;
            t.state.page = 1;
            t.load();
        });
        this.$root.on('change', '.aieo-attr-dt-badge', function () {
            t.state.badge = this.value || '';
            t.state.page = 1;
            t.load();
        });
        this.$root.on('click', 'thead th.sortable', function () {
            var key = $(this).data('sort-key');
            if (!key) return;
            if (t.state.sort === key) {
                t.state.dir = (t.state.dir === 'asc') ? 'desc' : 'asc';
            } else {
                t.state.sort = key;
                t.state.dir  = 'desc';
            }
            t.state.page = 1;
            t.load();
        });
        this.$root.on('click', '.aieo-attr-dt-pager button', function () {
            var p = parseInt($(this).data('page'), 10);
            if (!isNaN(p) && p > 0) { t.state.page = p; t.load(); }
        });
    };

    Table.prototype.load = function () {
        var t = this;
        var $body = this.$root.find('.aieo-attr-dt-body');
        $body.css('opacity', 0.4);
        $.post(CFG.ajaxUrl, {
            action:   'aieo_attribution_rows',
            nonce:    CFG.nonce,
            days:     t.state.days,
            page:     t.state.page,
            per_page: t.state.per_page,
            sort:     t.state.sort,
            dir:      t.state.dir,
            search:   t.state.search,
            badge:    t.state.badge,
        }).done(function (resp) {
            $body.css('opacity', 1);
            if (!resp || !resp.success) {
                $body.html('<div class="aieo-attr-dt-empty">' + esc(CFG.i18n.error || __( 'Error', 'ai-eshop-optimizer' )) + '</div>');
                return;
            }
            t.render(resp.data);
        }).fail(function () {
            $body.css('opacity', 1);
            $body.html('<div class="aieo-attr-dt-empty">' + esc(CFG.i18n.error || __( 'Error', 'ai-eshop-optimizer' )) + '</div>');
        });
    };

    Table.prototype.render = function (data) {
        var t = this;
        var $body = this.$root.find('.aieo-attr-dt-body');
        if (!data.rows.length) {
            $body.html('<div class="aieo-attr-dt-empty">' + esc(CFG.i18n.empty || __( 'No rows.', 'ai-eshop-optimizer' )) + '</div>');
            this.renderFooter(data);
            return;
        }
        var html = '<table class="widefat striped aieo-attr-dt-table"><thead><tr>';
        COLUMNS.forEach(function (col) {
            var cls = [];
            var key = col.sortKey || col.key;
            if (col.sortable) cls.push('sortable');
            if (t.state.sort === key) cls.push(t.state.dir === 'asc' ? 'sorted-asc' : 'sorted-desc');
            html += '<th class="' + cls.join(' ') + '" data-sort-key="' + key + '">'
                  + esc(col.label);
            if (col.sortable) {
                html += ' <span class="aieo-attr-dt-sort-ind">'
                      + (t.state.sort === key
                          ? (t.state.dir === 'asc' ? '▲' : '▼')
                          : '⇅')
                      + '</span>';
            }
            html += '</th>';
        });
        html += '</tr></thead><tbody>';
        data.rows.forEach(function (r) {
            html += '<tr>';
            COLUMNS.forEach(function (col) {
                html += '<td>' + renderCell(col, r) + '</td>';
            });
            html += '</tr>';
        });
        html += '</tbody></table>';
        $body.html(html);
        this.renderFooter(data);
    };

    Table.prototype.renderFooter = function (data) {
        var start = data.filtered === 0 ? 0 : (data.page - 1) * data.per_page + 1;
        var end   = Math.min(data.filtered, data.page * data.per_page);
        var tpl   = CFG.i18n.showing || 'Showing %1$d–%2$d of %3$d';
        var summary = tpl.replace('%1$d', start).replace('%2$d', end).replace('%3$d', data.filtered);
        if (data.filtered < data.total) {
            summary += ' (' + data.total + ' total)';
        }
        this.$root.find('.aieo-attr-dt-summary').text(summary);

        var pages = Math.max(1, Math.ceil(data.filtered / data.per_page));
        var $pager = this.$root.find('.aieo-attr-dt-pager').empty();
        if (pages <= 1) return;

        var cur = data.page;
        function btn(label, page, disabled, current) {
            return '<button type="button"'
                + (disabled ? ' disabled' : '')
                + (current  ? ' class="is-current"' : '')
                + ' data-page="' + page + '">' + esc(label) + '</button>';
        }
        $pager.append(btn('‹', cur - 1, cur <= 1, false));

        // Windowed page numbers (…  cur-2 cur-1 cur cur+1 cur+2  …)
        var start_p = Math.max(1, cur - 2);
        var end_p   = Math.min(pages, cur + 2);
        if (start_p > 1) {
            $pager.append(btn('1', 1, false, cur === 1));
            if (start_p > 2) $pager.append('<span class="aieo-attr-dt-gap">…</span>');
        }
        for (var p = start_p; p <= end_p; p++) {
            $pager.append(btn(String(p), p, false, p === cur));
        }
        if (end_p < pages) {
            if (end_p < pages - 1) $pager.append('<span class="aieo-attr-dt-gap">…</span>');
            $pager.append(btn(String(pages), pages, false, cur === pages));
        }
        $pager.append(btn('›', cur + 1, cur >= pages, false));
    };

    // ---------------------------------------------------------------------
    // Client-side sortable for the aggregate tables
    // (Conversion by surface / Slot performance / Top products / Top anchors).
    // These tables are capped at ≤20 rows each, so a simple in-DOM sort
    // is faster than round-tripping to the server.
    //
    // Each sortable <th> declares `data-sort-type="num"` or `"text"`.
    // Each <td> carries its raw sort value in `data-sort-value`
    // (emitted by PHP) — falls back to the cell's textContent.
    // ---------------------------------------------------------------------
    function bindSortableTable($table) {
        var $thead = $table.find('thead');
        $thead.on('click', 'th[data-sort-type]', function () {
            var $th = $(this);
            var idx = $th.index();
            var type = $th.data('sort-type') || 'text';
            var cur  = $th.hasClass('sorted-asc')
                ? 'asc'
                : ($th.hasClass('sorted-desc') ? 'desc' : null);
            var next = cur === 'asc' ? 'desc' : 'asc';

            $th.siblings().removeClass('sorted-asc sorted-desc')
                .find('.aieo-attr-dt-sort-ind').text('⇅');
            $th.removeClass('sorted-asc sorted-desc').addClass(
                next === 'asc' ? 'sorted-asc' : 'sorted-desc'
            );
            $th.find('.aieo-attr-dt-sort-ind').text(next === 'asc' ? '▲' : '▼');

            var $tbody = $table.find('tbody');
            var rows = $tbody.children('tr').toArray();

            // Skip sorting if the only row is the "no data" placeholder
            // (single <td colspan="N">).
            if (rows.length === 1 && rows[0].children.length <= 1) { return; }

            rows.sort(function (a, b) {
                var aCell = a.children[idx];
                var bCell = b.children[idx];
                if (!aCell || !bCell) return 0;
                var aVal = aCell.getAttribute('data-sort-value');
                var bVal = bCell.getAttribute('data-sort-value');
                if (aVal === null) aVal = (aCell.textContent || '').trim();
                if (bVal === null) bVal = (bCell.textContent || '').trim();
                if (type === 'num') {
                    var an = parseFloat(String(aVal).replace(/[^0-9.\-]/g, '')) || 0;
                    var bn = parseFloat(String(bVal).replace(/[^0-9.\-]/g, '')) || 0;
                    return next === 'asc' ? an - bn : bn - an;
                }
                // Text — locale-aware, Greek-friendly.
                var cmp = String(aVal).localeCompare(String(bVal), undefined, { sensitivity: 'base' });
                return next === 'asc' ? cmp : -cmp;
            });
            $tbody.append(rows);
        });
    }

    $(function () {
        var $root = $('#aieo-attr-detail-table');
        if ($root.length) { new Table($root); }
        $('.aieo-attr-sortable-table').each(function () { bindSortableTable($(this)); });
    });
})(jQuery);
