<?php
// envios.php
session_start();
include '../includes/session_control.php';
require_once '../cotizaciones/api/_node.php';

$token = cpn_node_token_or_fail();
$base = cpn_node_api_base();

function json_out($payload)
{
    header('Content-Type: application/json');
    $flags = 0;
    if (defined('JSON_UNESCAPED_UNICODE')) $flags |= JSON_UNESCAPED_UNICODE;
    if (defined('JSON_UNESCAPED_SLASHES')) $flags |= JSON_UNESCAPED_SLASHES;
    // Evita fallos por strings con bytes inválidos (típico cuando hay datos legacy en DB)
    if (defined('JSON_INVALID_UTF8_SUBSTITUTE')) $flags |= JSON_INVALID_UTF8_SUBSTITUTE;

    $json = json_encode($payload, $flags);
    if ($json === false) {
        // Último recurso: siempre responder JSON válido para que jQuery no caiga en .fail(parseerror)
        echo '{"ok":false,"error":"Respuesta JSON inválida"}';
        exit;
    }
    echo $json;
    exit;
}

// AJAX: listar productos para revisión de envíos
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'list') {
    $page = isset($_POST['page']) ? max(1, intval($_POST['page'])) : 1;
    $limit = isset($_POST['limit']) ? max(1, min(200, intval($_POST['limit']))) : 50;

    $filter_text = isset($_POST['filter_text']) ? trim((string)$_POST['filter_text']) : '';
    $filter_proveedor = isset($_POST['filter_proveedor']) && $_POST['filter_proveedor'] !== '' ? intval($_POST['filter_proveedor']) : null;

    // Defaults solicitados:
    // - idEstado = 1
    // - al menos una variación con stock
    // - diferencia cm3 > 500 o NULL
    $query = [
        'page' => $page,
        'limit' => $limit,
        'filter_text' => $filter_text,
        'filter_estado' => 1,
        'require_stock' => 1,
        // Nuevo criterio: checkListInfo contiene "Sin peso de envío" y/o diff > 500
        'filter_checklist_info_contains' => 'Sin peso de envío',
        'diff_min_cm3' => 500,
        'include_diff_null' => 0,
    ];
    if ($filter_proveedor) $query['filter_proveedor'] = $filter_proveedor;

    $url = $base . '/api/productos/envios/revision?' . http_build_query($query);
    $r = cpn_node_request('GET', $url, $token, null);

    if (!empty($r['ok'])) {
        json_out(['ok' => true, 'data' => $r['data'] ?? []]);
    }

    $msg = '';
    if (isset($r['error']['message'])) $msg = $r['error']['message'];
    elseif (isset($r['error'])) $msg = is_string($r['error']) ? $r['error'] : '';
    json_out(['ok' => false, 'error' => $msg ?: 'No se pudo listar']);
}

// AJAX: guardar cambios de envío para un producto
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'update_envio') {
    $idProducto = isset($_POST['idProducto']) ? intval($_POST['idProducto']) : 0;
    if (!$idProducto) json_out(['ok' => false, 'error' => 'ID inválido']);

    $payload = [];
    $fields = [
        'txtEmpaque',
        'largoCmCaja',
        'anchoCmCaja',
        'altoCmCaja',
        'undsCaja',
        'pesoKgCaja',

        'txtMedidas',
        'largoProductoEnvio',
        'anchoProductoEnvio',
        'altoProductoEnvio',

        'largoProductoEnvioAjustado',
        'anchoProductoEnvioAjustado',
        'altoProductoEnvioAjustado',
    ];
    foreach ($fields as $f) {
        if (isset($_POST[$f]) && $_POST[$f] !== '') {
            $payload[$f] = $_POST[$f];
        }
    }

    $r = cpn_node_request('POST', $base . '/api/productos/' . urlencode((string)$idProducto) . '/envio', $token, $payload);
    if (!empty($r['ok'])) {
        // refrescamos desde Node para devolver los valores recalculados
        $r2 = cpn_node_request('GET', $base . '/api/productos/' . urlencode((string)$idProducto) . '/envio', $token, null);
        json_out(['ok' => true, 'data' => $r2['data']['prod'] ?? null]);
    }

    $msg = '';
    if (isset($r['error']['message'])) $msg = $r['error']['message'];
    elseif (isset($r['error'])) $msg = is_string($r['error']) ? $r['error'] : '';
    json_out(['ok' => false, 'error' => $msg ?: 'No se pudo guardar']);
}

// AJAX: redimensionar (Node) y devolver datos refrescados
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'redimensionar') {
    $idProducto = isset($_POST['idProducto']) ? intval($_POST['idProducto']) : 0;
    if (!$idProducto) json_out(['ok' => false, 'error' => 'ID inválido']);

    $r = cpn_node_request('POST', $base . '/api/productos/' . urlencode((string)$idProducto) . '/envio/redimensionar', $token, []);
    if (!empty($r['ok'])) {
        $r2 = cpn_node_request('GET', $base . '/api/productos/' . urlencode((string)$idProducto) . '/envio', $token, null);
        json_out(['ok' => true, 'data' => $r2['data']['prod'] ?? null, 'calc' => ($r['data'] ?? null)]);
    }

    $msg = '';
    if (isset($r['error']['message'])) $msg = $r['error']['message'];
    elseif (isset($r['error'])) $msg = is_string($r['error']) ? $r['error'] : '';
    json_out(['ok' => false, 'error' => $msg ?: 'No se pudo redimensionar']);
}

// Meta para filtros (proveedores)
$rMeta = cpn_node_request('GET', $base . '/api/productos/meta/general', $token, null);
$meta = !empty($rMeta['ok']) ? ($rMeta['data'] ?? []) : [];
$proveedores = $meta['proveedores'] ?? [];

function opcionesLista($items)
{
    $opt = '';
    if (!is_array($items)) return $opt;
    foreach ($items as $r) {
        $id = (int)($r['id'] ?? 0);
        $label = (string)($r['nombre'] ?? '');
        if (!$id) continue;
        $opt .= "<option value=\"" . htmlspecialchars((string)$id) . "\">" . htmlspecialchars($label) . "</option>";
    }
    return $opt;
}
?>
<?php include '../templates/header.php'; ?>

<style>
    /* Compacto (solo esta pantalla) */
    #content .container-fluid .table {
        font-size: 12px;
    }

    #content .container-fluid .table th,
    #content .container-fluid .table td {
        padding: .25rem .35rem;
        line-height: 1.15;
    }

    #content .container-fluid .form-control,
    #content .container-fluid .custom-select,
    #content .container-fluid .form-select {
        font-size: 12px !important;
        padding: .2rem .4rem;
        height: calc(1.2em + .5rem + 2px);
    }

    #content .container-fluid .btn {
        font-size: 12px;
        padding: .25rem .5rem;
    }

    #content .container-fluid h1.h3,
    #content .container-fluid .h3 {
        font-size: 1.1rem;
    }
</style>

<div class="d-flex align-items-center justify-content-between mb-3">
    <h1 class="h3 mb-0 text-gray-800">Productos – Envíos (Revisión)</h1>
    <div class="small text-muted" id="enviosSummary"></div>
</div>

<div class="card shadow mb-3">
    <div class="card-body">
        <div class="form-row">
            <div class="form-group col-md-5">
                <label class="small">Buscar</label>
                <input type="text" id="filterText" class="form-control form-control-sm" placeholder="CPN / Ref Prov / Nombre">
            </div>
            <div class="form-group col-md-4">
                <label class="small">Proveedor</label>
                <select id="filterProveedor" class="form-control form-control-sm">
                    <option value="">Todos</option>
                    <?= opcionesLista($proveedores) ?>
                </select>
            </div>
            <div class="form-group col-md-2">
                <label class="small">Límite</label>
                <select id="limit" class="form-control form-control-sm">
                    <option value="25">25</option>
                    <option value="50" selected>50</option>
                    <option value="100">100</option>
                    <option value="200">200</option>
                </select>
            </div>
            <div class="form-group col-md-1 d-flex align-items-end">
                <button class="btn btn-sm btn-primary w-100" id="btnBuscar">Buscar</button>
            </div>
        </div>

        <div style="overflow-x:auto">
            <table class="table table-sm table-bordered mb-0" id="enviosTable">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Producto</th>
                        <th>Caja (L×A×H)</th>
                        <th>Unidad Ajustada (L×A×H)</th>
                        <th>Medidas envío</th>
                        <th>Dibujo</th>
                        <th>Acción</th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </div>

        <div class="d-flex justify-content-between align-items-center mt-2">
            <button class="btn btn-sm btn-outline-secondary" id="prevPage">«</button>
            <div class="small text-muted" id="pager"></div>
            <button class="btn btn-sm btn-outline-secondary" id="nextPage">»</button>
        </div>
    </div>
</div>

<style>
    /* Select2 dark (fallback si no está definido en css global) */
    .select2-container--default .select2-selection--single {
        background: #2d2f33;
        border: 1px solid #444;
        color: #fff;
        height: calc(1.5em + .5rem + 2px);
    }

    .select2-container--default .select2-selection--single .select2-selection__rendered {
        color: #fff;
        line-height: calc(1.5em + .5rem);
    }

    .select2-container--default .select2-selection--single .select2-selection__arrow b {
        border-color: #fff transparent transparent transparent;
    }

    .select2-container--default .select2-results__option {
        background: #2d2f33;
        color: #fff;
    }

    .select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
        background: #3b3f45;
        color: #fff;
    }

    .env-row-saving {
        opacity: 0.75;
    }

    .diff-null {
        background: rgba(255, 193, 7, 0.15);
    }
</style>

<script>
    (function() {
        function esc(v) {
            return String(v == null ? '' : v)
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#039;');
        }

        function num(v) {
            const n = Number(v);
            return Number.isFinite(n) ? n : null;
        }

        function fmt1(v) {
            const n = num(v);
            return n == null ? '' : n.toFixed(1);
        }

        function fmt4(v) {
            const n = num(v);
            return n == null ? '' : n.toFixed(4);
        }

        function computeMetricsFromProd(prod) {
            const Lc = num(prod.largoCmCaja),
                Ac = num(prod.anchoCmCaja),
                Hc = num(prod.altoCmCaja);
            const unds = num(prod.undsCaja);
            const volCaja = (Lc && Ac && Hc) ? (Lc * Ac * Hc) : null;
            const volCalc = (num(prod.volumenCm3ProductoAjustado) && unds) ? (num(prod.volumenCm3ProductoAjustado) * unds) : null;
            const diff = (Number.isFinite(volCaja) && Number.isFinite(volCalc)) ? (volCaja - volCalc) : null;

            const pesoRealUnd = num(prod.pesoKgProducto);
            const pesoVolUnd = (num(prod.largoProductoEnvioAjustado) && num(prod.anchoProductoEnvioAjustado) && num(prod.altoProductoEnvioAjustado)) ?
                ((num(prod.largoProductoEnvioAjustado) * num(prod.anchoProductoEnvioAjustado) * num(prod.altoProductoEnvioAjustado)) / 5000) :
                null;
            const pesoEnvUnd = (pesoRealUnd != null || pesoVolUnd != null) ?
                Math.max(pesoRealUnd || 0, pesoVolUnd || 0) :
                null;

            return {
                volCaja,
                volCalc,
                diff,
                pesoRealUnd,
                pesoVolUnd,
                pesoEnvUnd
            };
        }

        // Dibujo (mismo estilo/algoritmo que producto.php: drawPackage)
        function drawPackageLike(canvas, row, units) {
            if (!canvas) return;
            const ctx = canvas.getContext('2d');

            const Lc0 = num(row.largoCmCaja),
                Ac0 = num(row.anchoCmCaja),
                Hc0 = num(row.altoCmCaja);
            const uL0 = num(row.largoProductoEnvioAjustado),
                uA0 = num(row.anchoProductoEnvioAjustado),
                uH0 = num(row.altoProductoEnvioAjustado);
            if (!Lc0 || !Ac0 || !Hc0 || !uL0 || !uA0 || !uH0) {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.font = '10px sans-serif';
                ctx.fillStyle = 'rgba(0,0,0,0.45)';
                ctx.fillText('Sin datos', 6, 14);
                return;
            }

            const parts = String(row.acomodacion || '').split('x').map(Number);
            const n1 = Math.max(1, parts[0] || 1);
            const n2 = Math.max(1, parts[1] || 1);
            const n3 = Math.max(1, parts[2] || 1);

            const iso = (x, y, z) => ({
                x: x - y,
                y: (x + y) / 2 - z
            });

            const maxD = Math.max(Lc0, Ac0, Hc0);
            const s = Math.min((canvas.height * 0.4) / maxD, (canvas.width * 0.4) / maxD);
            const Lc = Lc0 * s,
                Ac = Ac0 * s,
                Hc = Hc0 * s;

            ctx.clearRect(0, 0, canvas.width, canvas.height);

            let [A, B, C, D, E, F, G, H] = [
                iso(0, 0, 0),
                iso(Lc, 0, 0),
                iso(Lc, Ac, 0),
                iso(0, Ac, 0),
                iso(0, 0, Hc),
                iso(Lc, 0, Hc),
                iso(Lc, Ac, Hc),
                iso(0, Ac, Hc)
            ];
            const pts = [A, B, C, D, E, F, G, H];
            const xs = pts.map(p => p.x),
                ys = pts.map(p => p.y);
            const offX = (canvas.width - (Math.max(...xs) - Math.min(...xs))) / 2 - Math.min(...xs);
            const offY = (canvas.height - (Math.max(...ys) - Math.min(...ys))) / 2 + Math.max(...ys);
            const mv = p => [p.x + offX, offY - p.y];

            // exterior
            ctx.strokeStyle = '#444';
            ctx.fillStyle = 'rgba(173,216,230,0.1)';
            [
                [A, B, C, D],
                [E, F, G, H],
                [A, E, H, D],
                [B, F, G, C]
            ].forEach(face => {
                ctx.beginPath();
                face.map(mv).forEach((pt, i) => i ? ctx.lineTo(...pt) : ctx.moveTo(...pt));
                ctx.closePath();
                ctx.stroke();
            });

            // interior units
            const uL = uL0 * s,
                uA = uA0 * s,
                uH = uH0 * s;
            const zSh = (Hc0 - uH0) * s;

            let drawn = 0;
            const maxUnits = Math.max(1, Number(units) || 1);
            for (let z = 0; z < n3 && drawn < maxUnits; z++) {
                for (let y = 0; y < n2 && drawn < maxUnits; y++) {
                    for (let x = 0; x < n1 && drawn < maxUnits; x++) {
                        drawn++;
                        const P = iso(x * uL, y * uA, z * uH + zSh);
                        const Q = iso((x + 1) * uL, y * uA, z * uH + zSh);
                        const R = iso((x + 1) * uL, (y + 1) * uA, z * uH + zSh);
                        const S = iso(x * uL, (y + 1) * uA, z * uH + zSh);
                        const U = iso(x * uL, y * uA, z * uH + uH + zSh);
                        const V = iso((x + 1) * uL, y * uA, z * uH + uH + zSh);
                        const W = iso((x + 1) * uL, (y + 1) * uA, z * uH + uH + zSh);
                        const X = iso(x * uL, (y + 1) * uA, z * uH + uH + zSh);

                        ctx.strokeStyle = '#c00';
                        ctx.fillStyle = 'rgba(232,62,140,0.6)';
                        [
                            [P, Q, R, S],
                            [U, V, W, X],
                            [P, U, X, S],
                            [Q, V, W, R]
                        ].forEach(face => {
                            ctx.beginPath();
                            face.map(mv).forEach((pt, i) => i ? ctx.lineTo(...pt) : ctx.moveTo(...pt));
                            ctx.closePath();
                            ctx.stroke();
                            ctx.fill();
                        });
                    }
                }
            }
        }

        let state = {
            page: 1,
            limit: 50,
            totalPages: 1
        };

        function load() {
            const payload = {
                action: 'list',
                page: state.page,
                limit: $('#limit').val(),
                filter_text: $('#filterText').val(),
                filter_proveedor: $('#filterProveedor').val(),
            };

            $('#enviosSummary').text('Cargando…');
            return $.ajax({
                    url: window.location.pathname,
                    type: 'POST',
                    dataType: 'json',
                    data: payload
                })
                .done(function(res) {
                    if (!res || !res.ok) {
                        $('#enviosSummary').text('Error');
                        alert((res && res.error) ? res.error : 'No se pudo cargar');
                        return;
                    }

                    const data = res.data || {};
                    state.limit = Number(data.limit) || 50;
                    state.totalPages = Number(data.totalPages) || 1;

                    const items = (data.items || []);
                    $('#enviosSummary').text('Registros: ' + (Number(data.totalCount) || 0));
                    $('#pager').text('Página ' + (Number(data.page) || 1) + ' / ' + state.totalPages);

                    const html = items.map(function(r) {
                        const diff = num(r.diffCm3);
                        const diffClass = (diff == null) ? 'diff-null' : '';
                        const diffTxt = (diff == null) ? 'NULL' : diff.toFixed(1);

                        const prodBlock = `
    <div>${esc(r.referenciaCPN || '')}</div>
    <div class="font-weight-bold">${esc(r.nombre || '')}</div>
    <div class="text-muted">${esc(r.proveedor || '')}</div>
    <div class="text-muted">Stock: ${esc(r.inventario || 0)}</div>
                                                `.trim();

                        return `
<tr data-id="${esc(r.idProducto)}" class="${diffClass}">
    <td>${esc(r.idProducto)}</td>

    <td style="min-width:260px">${prodBlock}</td>

    <td style="min-width:320px">
        <div class="mb-1">
            <textarea class="form-control form-control-sm" name="txtEmpaque" rows="2" placeholder="Empaque">${esc(r.txtEmpaque || '')}</textarea>
        </div>
        <div class="d-flex flex-wrap" style="gap:6px">
            <div>
                <div class="small text-muted">L</div>
                <input class="form-control form-control-sm" style="width:78px" name="largoCmCaja" value="${esc(fmt1(r.largoCmCaja))}">
            </div>
            <div>
                <div class="small text-muted">A</div>
                <input class="form-control form-control-sm" style="width:78px" name="anchoCmCaja" value="${esc(fmt1(r.anchoCmCaja))}">
            </div>
            <div>
                <div class="small text-muted">H</div>
                <input class="form-control form-control-sm" style="width:78px" name="altoCmCaja" value="${esc(fmt1(r.altoCmCaja))}">
            </div>
            <div>
                <div class="small text-muted">Unds</div>
                <input class="form-control form-control-sm" style="width:72px" name="undsCaja" value="${esc(r.undsCaja ?? '')}">
            </div>
            <div>
                <div class="small text-muted">Peso kg</div>
                <input class="form-control form-control-sm" style="width:86px" name="pesoKgCaja" value="${esc(r.pesoKgCaja ?? '')}">
            </div>
        </div>
    </td>

    <td style="min-width:360px">
        <div class="mb-1">
            <textarea class="form-control form-control-sm" name="txtMedidas" rows="2" placeholder="Medidas">${esc(r.txtMedidas || '')}</textarea>
        </div>

        <div class="small text-muted">Original</div>
        <div class="d-flex flex-wrap mb-1" style="gap:6px">
            <input class="form-control form-control-sm" style="width:78px" name="largoProductoEnvio" value="${esc(fmt1(r.largoProductoEnvio))}" placeholder="L">
            <input class="form-control form-control-sm" style="width:78px" name="anchoProductoEnvio" value="${esc(fmt1(r.anchoProductoEnvio))}" placeholder="A">
            <input class="form-control form-control-sm" style="width:78px" name="altoProductoEnvio" value="${esc(fmt1(r.altoProductoEnvio))}" placeholder="H">
        </div>

        <div class="d-flex align-items-center justify-content-between">
            <div class="small text-muted">Ajustada</div>
            <button class="btn btn-sm btn-outline-secondary btn-redimensionar" type="button">Redimensionar</button>
        </div>
        <div class="d-flex flex-wrap" style="gap:6px">
            <input class="form-control form-control-sm" style="width:78px" name="largoProductoEnvioAjustado" value="${esc(fmt1(r.largoProductoEnvioAjustado))}" placeholder="L">
            <input class="form-control form-control-sm" style="width:78px" name="anchoProductoEnvioAjustado" value="${esc(fmt1(r.anchoProductoEnvioAjustado))}" placeholder="A">
            <input class="form-control form-control-sm" style="width:78px" name="altoProductoEnvioAjustado" value="${esc(fmt1(r.altoProductoEnvioAjustado))}" placeholder="H">
        </div>
    </td>

    <td style="min-width:220px">
        <div class="small text-muted">Acomodación: <span class="js-acomodacion">${esc(r.acomodacion || '')}</span></div>
        <div class="small text-muted">Vol Caja: <span class="js-volCaja">${esc(fmt1(r.volCajaCm3))}</span></div>
        <div class="small text-muted">Vol Calc: <span class="js-volCalc">${esc(fmt1(r.volCalcCm3))}</span></div>
        <div class="small js-diff-row ${diff == null ? 'text-warning' : (diff >= 0 ? 'text-success' : 'text-danger')}">Diff: <span class="js-diff">${esc(diffTxt)}</span></div>
        <div class="small text-muted">Peso real und: <span class="js-pesoRealUnd">${esc(fmt4(r.pesoKgProducto ?? r.pesoRealUnd))}</span></div>
        <div class="small text-muted">Peso vol und: <span class="js-pesoVolUnd">${esc(fmt4(r.pesoVolUnd))}</span></div>
        <div class="small font-weight-bold">Peso env und: <span class="js-pesoEnvUnd">${esc(fmt4(r.pesoEnvUnd))}</span></div>
    </td>

    <td><canvas width="140" height="90"></canvas></td>

    <td style="min-width:180px">
        <div class="d-flex flex-wrap" style="gap:6px">
            <button class="btn btn-sm btn-success btn-save" type="button">Guardar</button>
            <a class="btn btn-sm btn-outline-primary" target="_blank" href="/productos/producto.php?id=${esc(r.idProducto)}">Abrir</a>
        </div>
    </td>
</tr>`;
                    }).join('');

                    const $tb = $('#enviosTable tbody');
                    $tb.html(html);

                    // Dibujo lazy: solo lo visible
                    requestAnimationFrame(function() {
                        $('#enviosTable tbody tr').each(function() {
                            const $tr = $(this);
                            const rect = this.getBoundingClientRect();
                            if (rect.bottom < 0 || rect.top > window.innerHeight + 100) return;

                            const row = items.find(x => String(x.idProducto) === String($tr.data('id')));
                            if (!row) return;
                            drawPackageLike($tr.find('canvas')[0], row, 1);
                        });
                    });
                })
                .fail(function(xhr) {
                    console.error(xhr && xhr.responseText);
                    $('#enviosSummary').text('Error');
                    alert('Error de red');
                });
        }

        function collectRowPayload($tr) {
            const payload = {
                action: 'update_envio',
                idProducto: $tr.data('id')
            };
            $tr.find('input[name]').each(function() {
                payload[$(this).attr('name')] = $(this).val();
            });
            $tr.find('textarea[name]').each(function() {
                payload[$(this).attr('name')] = $(this).val();
            });
            return payload;
        }

        function updateRowFromProd($tr, prod) {
            const m = computeMetricsFromProd(prod);

            $tr.toggleClass('diff-null', m.diff == null);
            $tr.find('.js-acomodacion').text(prod.acomodacion || '');

            $tr.find('.js-volCaja').text(m.volCaja == null ? '' : m.volCaja.toFixed(1));
            $tr.find('.js-volCalc').text(m.volCalc == null ? '' : m.volCalc.toFixed(1));
            $tr.find('.js-diff').text(m.diff == null ? 'NULL' : m.diff.toFixed(1));

            $tr.find('.js-diff-row')
                .removeClass('text-success text-danger text-warning')
                .addClass(
                    m.diff == null ?
                    'text-warning' :
                    (m.diff >= 0 ? 'text-success' : 'text-danger')
                );

            $tr.find('.js-pesoRealUnd').text(m.pesoRealUnd == null ? '' : m.pesoRealUnd.toFixed(4));
            $tr.find('.js-pesoVolUnd').text(m.pesoVolUnd == null ? '' : m.pesoVolUnd.toFixed(4));
            $tr.find('.js-pesoEnvUnd').text(m.pesoEnvUnd == null ? '' : m.pesoEnvUnd.toFixed(4));

            // Re-dibujo (mismo que producto.php)
            drawPackageLike($tr.find('canvas')[0], {
                largoCmCaja: prod.largoCmCaja,
                anchoCmCaja: prod.anchoCmCaja,
                altoCmCaja: prod.altoCmCaja,
                largoProductoEnvioAjustado: prod.largoProductoEnvioAjustado,
                anchoProductoEnvioAjustado: prod.anchoProductoEnvioAjustado,
                altoProductoEnvioAjustado: prod.altoProductoEnvioAjustado,
                acomodacion: prod.acomodacion
            }, 1);
        }

        function doRowSave($tr) {
            if (!$tr || !$tr.length) return;
            if ($tr.data('saving') === 1) return;

            const payload = collectRowPayload($tr);
            $tr.data('saving', 1);
            $tr.addClass('env-row-saving');

            return $.ajax({
                    url: window.location.pathname,
                    type: 'POST',
                    dataType: 'json',
                    data: payload
                })
                .done(function(res) {
                    if (!res || !res.ok) {
                        alert((res && res.error) ? res.error : 'No se pudo guardar');
                        return;
                    }
                    const prod = res.data || {};
                    updateRowFromProd($tr, prod);
                })
                .fail(function(xhr) {
                    console.error(xhr && xhr.responseText);
                    alert('Error de red al guardar');
                })
                .always(function() {
                    $tr.data('saving', 0);
                    $tr.removeClass('env-row-saving');
                });
        }

        function scheduleRowSave($tr, immediate) {
            clearTimeout($tr.data('saveTimer'));
            const delay = immediate ? 0 : 700;
            const t = setTimeout(function() {
                doRowSave($tr);
            }, delay);
            $tr.data('saveTimer', t);
        }

        $(function() {
            if ($.fn.select2) {
                $('#filterProveedor').select2({
                    placeholder: 'Proveedor',
                    allowClear: true,
                    width: '100%'
                });
            }

            $('#btnBuscar').on('click', function() {
                state.page = 1;
                load();
            });

            $('#filterText').on('keydown', function(e) {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    state.page = 1;
                    load();
                }
            });

            $('#prevPage').on('click', function() {
                state.page = Math.max(1, state.page - 1);
                load();
            });
            $('#nextPage').on('click', function() {
                state.page = Math.min(state.totalPages || 1, state.page + 1);
                load();
            });

            // Live-save: escribe y guarda sin recargar (debounce)
            $('#enviosTable').on('input', 'input[name], textarea[name]', function() {
                const $tr = $(this).closest('tr');
                scheduleRowSave($tr, false);
            });

            // En blur/change, guardamos inmediato
            $('#enviosTable').on('change blur', 'input[name], textarea[name]', function() {
                const $tr = $(this).closest('tr');
                scheduleRowSave($tr, true);
            });

            // Botón Guardar (sigue existiendo como respaldo)
            $('#enviosTable').on('click', '.btn-save', function(e) {
                e.preventDefault();
                e.stopPropagation();
                doRowSave($(this).closest('tr'));
            });

            $('#enviosTable').on('click', '.btn-redimensionar', function(e) {
                e.preventDefault();
                e.stopPropagation();
                const $tr = $(this).closest('tr');
                const idProducto = $tr.data('id');
                $tr.addClass('env-row-saving');

                $.ajax({
                        url: window.location.pathname,
                        type: 'POST',
                        dataType: 'json',
                        data: {
                            action: 'redimensionar',
                            idProducto: idProducto
                        }
                    })
                    .done(function(res) {
                        if (!res || !res.ok) {
                            alert((res && res.error) ? res.error : 'No se pudo redimensionar');
                            return;
                        }

                        const prod = res.data || {};

                        // Actualiza inputs ajustados/acomedación + métricas
                        $tr.find('input[name="largoProductoEnvioAjustado"]').val(fmt1(prod.largoProductoEnvioAjustado));
                        $tr.find('input[name="anchoProductoEnvioAjustado"]').val(fmt1(prod.anchoProductoEnvioAjustado));
                        $tr.find('input[name="altoProductoEnvioAjustado"]').val(fmt1(prod.altoProductoEnvioAjustado));

                        updateRowFromProd($tr, prod);
                    })
                    .fail(function(xhr) {
                        console.error(xhr && xhr.responseText);
                        alert('Error de red al redimensionar');
                    })
                    .always(function() {
                        $tr.removeClass('env-row-saving');
                    });
            });

            // Inicial
            load();
        });
    })();
</script>

<?php include '../templates/footer.php'; ?>