<?php
/**
 * orden_salida_botella.php
 * ============================================================
 * BReport · Botella
 * PDF limpio de ORDEN DE SALIDA con doble formato:
 * - Carta: documento formal para archivo / cliente.
 * - Ticket térmico 80mm: comprobante compacto para impresora térmica.
 *
 * Uso:
 *   orden_salida_botella.php?order_id=137&outbound_id=653&folio=OSV-000137
 *   orden_salida_botella.php?order_id=137&outbound_id=653&folio=OSV-000137&formato=ticket
 * ============================================================
 */

declare(strict_types=1);

ini_set('display_errors', '0');
ini_set('display_startup_errors', '0');
error_reporting(E_ALL);

require_once __DIR__ . '/includes/db.php';
require_once __DIR__ . '/includes/auth.php';
require_once __DIR__ . '/lib/fpdf.php';

function osb_text($s): string {
    if ($s === null) return '';
    $s = (string)$s;
    $conv = @iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s);
    return $conv !== false ? $conv : $s;
}

function osb_safe_filename(string $name): string {
    $name = preg_replace('/[^A-Za-z0-9_\-]/', '_', $name);
    $name = trim((string)$name, '_');
    return $name !== '' ? $name : 'orden_salida_botella';
}

function osb_table_exists(PDO $pdo, string $table): bool {
    $st = $pdo->prepare("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?");
    $st->execute([$table]);
    return (int)$st->fetchColumn() > 0;
}

function osb_column_exists(PDO $pdo, string $table, string $column): bool {
    $st = $pdo->prepare("SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?");
    $st->execute([$table, $column]);
    return (int)$st->fetchColumn() > 0;
}

function osb_scope(): array {
    if (function_exists('scope')) {
        $s = scope();
        return [
            'company_id' => (int)($s['company_id'] ?? 0),
            'location_id' => (int)($s['location_id'] ?? 0),
        ];
    }
    return ['company_id' => 0, 'location_id' => 0];
}

function osb_normalize_folio(array $order): string {
    $folio = trim((string)($order['sales_order_ref'] ?? ''));
    if ($folio !== '') return $folio;
    $id = (int)($order['id'] ?? 0);
    return $id > 0 ? ('OSV-' . str_pad((string)$id, 6, '0', STR_PAD_LEFT)) : 'OSV';
}

function osb_requested_format(): string {
    $fmt = mb_strtolower(trim((string)($_GET['formato'] ?? $_GET['format'] ?? $_GET['tipo'] ?? 'carta')), 'UTF-8');
    if (in_array($fmt, ['ticket', 'termico', 'térmico', 'thermal', '80', '80mm'], true)) return 'ticket';
    return 'carta';
}

function osb_find_order(PDO $pdo, int $orderId, int $outboundId, string $folio, int $companyId, int $locationId): ?array {
    $where = [];
    $params = [];

    if ($orderId > 0) { $where[] = 'o.id = ?'; $params[] = $orderId; }
    if ($outboundId > 0) { $where[] = 'o.outbound_id = ?'; $params[] = $outboundId; }
    if ($folio !== '') { $where[] = 'o.sales_order_ref = ?'; $params[] = $folio; }
    if (!$where) return null;

    $scopeSql = '';
    if ($companyId > 0 && $locationId > 0) {
        $scopeSql = ' AND o.company_id = ? AND o.location_id = ? ';
        $params[] = $companyId;
        $params[] = $locationId;
    }

    $customerCodeSelect = osb_column_exists($pdo, 'sales_customers', 'customer_code') ? 'c.customer_code' : "'' AS customer_code";

    $sql = "
        SELECT
            o.*,
            {$customerCodeSelect},
            c.business_name,
            c.contact_name,
            c.phone
        FROM sales_orders o
        JOIN sales_customers c ON c.id = o.customer_id
        WHERE (" . implode(' OR ', $where) . ")
        {$scopeSql}
        ORDER BY o.id DESC
        LIMIT 1
    ";

    $st = $pdo->prepare($sql);
    $st->execute($params);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    return $row ?: null;
}

function osb_line_count(FPDF $pdf, string $text, float $width): int {
    $txt = osb_text($text);
    if ($txt === '') return 1;
    $usable = max(1.0, $width - 4.0);
    $lines = 1;
    $buffer = '';
    $len = strlen($txt);
    for ($i = 0; $i < $len; $i++) {
        $ch = $txt[$i];
        if ($ch === "\n") { $lines++; $buffer = ''; continue; }
        $candidate = $buffer . $ch;
        if ($buffer !== '' && $pdf->GetStringWidth($candidate) > $usable) {
            $lines++;
            $buffer = $ch;
        } else {
            $buffer = $candidate;
        }
    }
    return max(1, $lines);
}

function osb_table_header(FPDF $pdf, array $w): void {
    $pdf->SetFillColor(235, 241, 250);
    $pdf->SetDrawColor(80, 90, 105);
    $pdf->SetTextColor(0, 20, 50);
    $pdf->SetFont('Arial', 'B', 9);
    $headers = ['OC', 'Artículo', 'Tarimas', 'Pz/Paq', 'Total piezas'];
    foreach ($headers as $i => $header) {
        $pdf->Cell($w[$i], 8, osb_text($header), 1, $i === count($headers) - 1 ? 1 : 0, 'C', true);
    }
    $pdf->SetTextColor(0, 0, 0);
}

function osb_table_row(FPDF $pdf, array $w, array $values): void {
    $lineHeight = 5.2;
    $maxLines = 1;
    foreach ($values as $i => $v) $maxLines = max($maxLines, osb_line_count($pdf, (string)$v, (float)$w[$i]));
    $rowHeight = max(8.0, ($maxLines * $lineHeight) + 3.0);

    if ($pdf->GetY() + $rowHeight > 252) {
        $pdf->AddPage();
        osb_table_header($pdf, $w);
    }

    $x0 = $pdf->GetX();
    $y = $pdf->GetY();
    $x = $x0;
    $align = ['C', 'L', 'C', 'C', 'C'];

    $pdf->SetFont('Arial', '', 9);
    foreach ($values as $i => $v) {
        $pdf->Rect($x, $y, (float)$w[$i], $rowHeight);
        $pdf->SetXY($x + 1.5, $y + 1.5);
        $pdf->MultiCell((float)$w[$i] - 3.0, $lineHeight, osb_text((string)$v), 0, $align[$i]);
        $x += (float)$w[$i];
    }
    $pdf->SetXY($x0, $y + $rowHeight);
}

function osb_clean_note(?string $text): string {
    $text = trim((string)($text ?? ''));
    if ($text === '') return '';

    $text = str_replace(["\r\n", "\r"], "\n", $text);
    $text = preg_replace('/\s*\|\s*/u', "\n", (string)$text);
    $lines = array_values(array_filter(array_map('trim', explode("\n", (string)$text)), static fn($v) => $v !== ''));

    $keep = [];
    foreach ($lines as $line) {
        $upper = mb_strtoupper($line, 'UTF-8');
        $autoPrefixes = [
            'ORDEN DE SALIDA BOTELLA CREADA DESDE VENTAS',
            'ORDEN DE SALIDA CREADA DESDE ALMACÉN BOTELLA',
            'ORDEN DE SALIDA CREADA DESDE ALMACEN BOTELLA',
            'PEDIDO VENTAS #',
            'FOLIO VENTAS:',
            'CLIENTE/DESTINO:',
            'RUTA DESTINO INVENTARIO:',
            'CARGA BOTELLA A RUTA MÓVIL',
            'CARGA BOTELLA A RUTA MOVIL',
            'UNIDAD A CARGAR:',
            'CHOFER:',
            'FECHA/HORA SALIDA:',
            'SALIDA:',
            'REFERENCIA SALIDA:',
            'CANAL:',
        ];
        $skip = false;
        foreach ($autoPrefixes as $prefix) {
            if (str_starts_with($upper, $prefix)) { $skip = true; break; }
        }
        if ($skip) continue;
        if (str_starts_with($upper, 'RUTA:')) continue;

        foreach (['Notas Ventas:', 'Notas Almacén:', 'Notas Almacen:', 'Notas ventas:', 'Notas almacén:', 'Notas almacen:'] as $prefix) {
            if (mb_strtoupper(mb_substr($line, 0, mb_strlen($prefix, 'UTF-8'), 'UTF-8'), 'UTF-8') === mb_strtoupper($prefix, 'UTF-8')) {
                $line = trim(mb_substr($line, mb_strlen($prefix, 'UTF-8'), null, 'UTF-8'));
            }
        }
        if ($line !== '') $keep[] = $line;
    }

    return mb_substr(trim(implode("\n", array_unique($keep))), 0, 900, 'UTF-8');
}

function osb_extract_labeled_note(string $text, string $label): string {
    $text = trim($text);
    if ($text === '') return '';
    $labels = ['Notas Ventas:', 'Notas Almacén:', 'Notas Almacen:', 'Notas ventas:', 'Notas almacén:', 'Notas almacen:'];
    $escapedLabels = array_map(static fn($v) => preg_quote($v, '/'), $labels);
    $labelRegex = preg_quote($label, '/');
    $nextRegex = implode('|', $escapedLabels);
    if (preg_match('/' . $labelRegex . '\s*(.*?)(?=\s*\|\s*(?:' . $nextRegex . ')|\s*(?:' . $nextRegex . ')|$)/isu', $text, $m)) {
        return trim((string)$m[1], " \t\n\r\0\x0B|");
    }
    return '';
}

function osb_multicell_section(FPDF $pdf, string $title, string $text): void {
    $text = trim($text);
    if ($text === '') return;
    $pdf->SetFont('Arial', 'B', 9);
    $pdf->Cell(0, 5.5, osb_text($title), 0, 1);
    $pdf->SetFont('Arial', '', 9);
    $pdf->MultiCell(0, 5.2, osb_text($text));
    $pdf->Ln(1);
}

function osb_items(PDO $pdo, array $order): array {
    $hasItemPo = osb_column_exists($pdo, 'sales_order_items', 'purchase_order');
    $hasPkgId = osb_column_exists($pdo, 'sales_order_items', 'packaging_option_id');
    $hasPackages = osb_column_exists($pdo, 'sales_order_items', 'packages_qty');
    $hasPallets = osb_column_exists($pdo, 'sales_order_items', 'pallets_qty');
    $hasPackTable = osb_table_exists($pdo, 'product_packaging_options');
    $hasProductPieces = osb_column_exists($pdo, 'products', 'pieces_per_package');
    $hasProductPackages = osb_column_exists($pdo, 'products', 'packages_per_pallet');

    $selectPo = $hasItemPo ? 'i.purchase_order AS purchase_order' : 'NULL AS purchase_order';
    $selectPkgId = $hasPkgId ? 'i.packaging_option_id AS packaging_option_id' : 'NULL AS packaging_option_id';
    $selectPackages = $hasPackages ? 'i.packages_qty AS packages_qty' : '0 AS packages_qty';
    $selectPallets = $hasPallets ? 'i.pallets_qty AS pallets_qty' : '0 AS pallets_qty';
    $joinPkg = ($hasPkgId && $hasPackTable) ? 'LEFT JOIN product_packaging_options po ON po.id = i.packaging_option_id AND po.company_id = p.company_id' : '';

    $pieceParts = [];
    $packParts = [];
    if ($hasPkgId && $hasPackTable) {
        $pieceParts[] = 'NULLIF(po.pieces_per_package,0)';
        $packParts[] = 'NULLIF(po.packages_per_pallet,0)';
    }
    if ($hasProductPieces) $pieceParts[] = 'NULLIF(p.pieces_per_package,0)';
    if ($hasProductPackages) $packParts[] = 'NULLIF(p.packages_per_pallet,0)';

    $piecesExpr = 'COALESCE(' . ($pieceParts ? implode(',', $pieceParts) . ',' : '') . '0)';
    $packsPerPalletExpr = 'COALESCE(' . ($packParts ? implode(',', $packParts) . ',' : '') . '0)';

    $sql = "
        SELECT
            {$selectPo},
            i.product_id,
            {$selectPkgId},
            {$selectPackages},
            {$selectPallets},
            i.qty,
            p.sku,
            p.name AS product_name,
            {$piecesExpr} AS pieces_per_package,
            {$packsPerPalletExpr} AS packages_per_pallet
        FROM sales_order_items i
        JOIN products p ON p.id = i.product_id
        {$joinPkg}
        WHERE i.order_id = ?
        ORDER BY purchase_order, p.sku, p.name
    ";
    $st = $pdo->prepare($sql);
    $st->execute([(int)$order['id']]);
    $rows = $st->fetchAll(PDO::FETCH_ASSOC);

    $grouped = [];
    foreach ($rows as $r) {
        $oc = trim((string)($r['purchase_order'] ?? ''));
        if ($oc === '') $oc = trim((string)($order['purchase_order'] ?? ''));
        if ($oc === '') $oc = '-';

        $piecesPerPackage = (float)($r['pieces_per_package'] ?? 0);
        $packagesPerPallet = (float)($r['packages_per_pallet'] ?? 0);
        $qty = (float)($r['qty'] ?? 0);
        $packages = (float)($r['packages_qty'] ?? 0);
        $pallets = (float)($r['pallets_qty'] ?? 0);

        if ($packages <= 0 && $piecesPerPackage > 0 && $qty > 0) $packages = $qty / $piecesPerPackage;
        if ($pallets <= 0 && $packagesPerPallet > 0 && $packages > 0) $pallets = $packages / $packagesPerPallet;

        $key = implode('|', [$oc, (int)$r['product_id'], (int)($r['packaging_option_id'] ?? 0), (int)$piecesPerPackage]);
        if (!isset($grouped[$key])) {
            $grouped[$key] = [
                'oc' => $oc,
                'sku' => (string)($r['sku'] ?? ''),
                'product_name' => (string)($r['product_name'] ?? ''),
                'pallets_qty' => 0.0,
                'pieces_per_package' => $piecesPerPackage,
                'total_pieces' => 0.0,
            ];
        }
        $grouped[$key]['pallets_qty'] += $pallets;
        $grouped[$key]['total_pieces'] += $qty;
    }

    return array_values($grouped);
}

function osb_render_carta(array $ctx): FPDF {
    $pdf = new FPDF('P', 'mm', 'Letter');
    $pdf->SetMargins(10, 10, 10);
    $pdf->AddPage();

    $logoPath = __DIR__ . '/assets/blanquita.png';
    if (is_file($logoPath)) $pdf->Image($logoPath, 10, 8, 42);

    $pdf->SetY(14);
    $pdf->SetFont('Arial', 'B', 15);
    $pdf->Cell(0, 8, osb_text('ORDEN DE SALIDA'), 0, 1, 'C');
    $pdf->SetFont('Arial', '', 9);
    $pdf->Cell(0, 5, osb_text('Documento para surtido / entrega'), 0, 1, 'C');
    $pdf->Ln(4);

    $pdf->SetDrawColor(210, 220, 232);
    $pdf->SetFillColor(244, 247, 251);
    $y = $pdf->GetY();
    $pdf->Rect(10, $y, 96, 31, 'DF');
    $pdf->Rect(110, $y, 96, 31, 'DF');

    $pdf->SetXY(14, $y + 4);
    $pdf->SetFont('Arial', 'B', 9);
    $pdf->Cell(0, 5, osb_text('Orden de salida'), 0, 1);
    $pdf->SetFont('Arial', '', 9);
    $pdf->SetX(14);
    $pdf->Cell(0, 5, osb_text('Salida sistema: ' . $ctx['folioSalida']), 0, 1);
    $pdf->SetX(14);
    $pdf->Cell(0, 5, osb_text('Folio venta: ' . $ctx['folioVenta']), 0, 1);
    if ($ctx['fechaSalida'] !== '') { $pdf->SetX(14); $pdf->Cell(0, 5, osb_text('Fecha salida: ' . $ctx['fechaSalida']), 0, 1); }

    $pdf->SetXY(114, $y + 4);
    $pdf->SetFont('Arial', 'B', 9);
    $pdf->Cell(0, 5, osb_text('Cliente'), 0, 1);
    $pdf->SetFont('Arial', '', 9);
    $pdf->SetX(114);
    $pdf->Cell(0, 5, osb_text(($ctx['clienteCodigo'] !== '' ? $ctx['clienteCodigo'] . ' · ' : '') . ($ctx['cliente'] !== '' ? $ctx['cliente'] : '-')), 0, 1);
    if ($ctx['contacto'] !== '' || $ctx['telefono'] !== '') {
        $pdf->SetX(114);
        $pdf->Cell(0, 5, osb_text(trim($ctx['contacto'] . ($ctx['telefono'] !== '' ? ' · ' . $ctx['telefono'] : ''))), 0, 1);
    }
    $pdf->SetX(114);
    $pdf->Cell(0, 5, osb_text('Solicitada: ' . ($ctx['fechaSolicitada'] !== '' ? $ctx['fechaSolicitada'] : '-') . ($ctx['horaSolicitada'] !== '' ? ' ' . $ctx['horaSolicitada'] : '')), 0, 1);

    $pdf->SetY($y + 35);
    $pdf->SetFont('Arial', 'B', 9);
    $pdf->Cell(0, 5.5, osb_text('Dirección de entrega'), 0, 1);
    $pdf->SetFont('Arial', '', 9);
    $pdf->MultiCell(0, 5.2, osb_text($ctx['direccion'] !== '' ? $ctx['direccion'] : '-'));
    $pdf->Ln(1);

    osb_multicell_section($pdf, 'Notas de Ventas', $ctx['ventasNote']);
    osb_multicell_section($pdf, 'Notas de Almacén', $ctx['almacenNote']);

    $pdf->Ln(2);
    $pdf->SetFont('Arial', 'B', 10);
    $pdf->Cell(0, 6, osb_text('Detalle de artículos por OC'), 0, 1);

    $widths = [33, 78, 25, 25, 35];
    osb_table_header($pdf, $widths);
    if (!$ctx['items']) {
        osb_table_row($pdf, $widths, ['-', 'Sin artículos registrados', '-', '-', '-']);
    } else {
        foreach ($ctx['items'] as $it) {
            $article = trim((string)$it['sku'] . "\n" . (string)$it['product_name']);
            osb_table_row($pdf, $widths, [
                (string)$it['oc'],
                $article,
                number_format((float)$it['pallets_qty'], 0, '.', ','),
                number_format((float)$it['pieces_per_package'], 0, '.', ','),
                number_format((float)$it['total_pieces'], 0, '.', ','),
            ]);
        }
    }

    $totalPallets = array_reduce($ctx['items'], static fn($a, $r) => $a + (float)$r['pallets_qty'], 0.0);
    $totalPieces = array_reduce($ctx['items'], static fn($a, $r) => $a + (float)$r['total_pieces'], 0.0);
    $pdf->SetFont('Arial', 'B', 9);
    $pdf->SetFillColor(244, 247, 251);
    $pdf->Cell($widths[0] + $widths[1], 8, osb_text('Totales'), 1, 0, 'R', true);
    $pdf->Cell($widths[2], 8, osb_text(number_format($totalPallets, 0, '.', ',')), 1, 0, 'C', true);
    $pdf->Cell($widths[3], 8, '', 1, 0, 'C', true);
    $pdf->Cell($widths[4], 8, osb_text(number_format($totalPieces, 0, '.', ',')), 1, 1, 'C', true);

    $pdf->Ln(12);
    $pdf->SetFont('Arial', '', 9);
    $pdf->Cell(0, 6, osb_text('Nombre y firma de quien recibe: _______________________________________________'), 0, 1);
    $pdf->Ln(8);
    $pdf->Cell(0, 6, osb_text('Nombre y firma de quien entrega: _____________________________________________   Fecha: ____/____/______'), 0, 1);

    return $pdf;
}

function osb_ticket_line(FPDF $pdf): void {
    $pdf->SetFont('Arial', '', 7);
    $pdf->Cell(0, 3, osb_text(str_repeat('-', 42)), 0, 1, 'C');
}

function osb_ticket_kv(FPDF $pdf, string $key, string $value): void {
    $value = trim($value);
    if ($value === '') $value = '-';
    $pdf->SetFont('Arial', 'B', 7.5);
    $pdf->Cell(16, 4, osb_text($key . ':'), 0, 0, 'L');
    $pdf->SetFont('Arial', '', 7.5);
    $x = $pdf->GetX();
    $y = $pdf->GetY();
    $pdf->SetXY($x, $y);
    $pdf->MultiCell(55, 4, osb_text($value), 0, 'L');
}

function osb_ticket_section(FPDF $pdf, string $title, string $text): void {
    $text = trim($text);
    if ($text === '') return;
    osb_ticket_line($pdf);
    $pdf->SetFont('Arial', 'B', 8);
    $pdf->Cell(0, 4.5, osb_text($title), 0, 1, 'L');
    $pdf->SetFont('Arial', '', 7.5);
    $pdf->MultiCell(0, 4, osb_text($text), 0, 'L');
}

function osb_render_ticket(array $ctx): FPDF {
    // 80mm es el ancho común de ticket térmico. Alto amplio para permitir AutoPageBreak.
    $pdf = new FPDF('P', 'mm', [80, 297]);
    $pdf->SetMargins(4, 5, 4);
    $pdf->SetAutoPageBreak(true, 8);
    $pdf->AddPage();

    $logoPath = __DIR__ . '/assets/blanquita.png';
    if (is_file($logoPath)) $pdf->Image($logoPath, 24, 4, 32);
    if (is_file($logoPath)) $pdf->Ln(17);

    $pdf->SetFont('Arial', 'B', 11);
    $pdf->Cell(0, 5, osb_text('ORDEN DE SALIDA'), 0, 1, 'C');
    $pdf->SetFont('Arial', '', 7.5);
    $pdf->Cell(0, 4, osb_text('BReport · Botella'), 0, 1, 'C');
    osb_ticket_line($pdf);

    osb_ticket_kv($pdf, 'Salida', $ctx['folioSalida']);
    osb_ticket_kv($pdf, 'Venta', $ctx['folioVenta']);
    if ($ctx['fechaSalida'] !== '') osb_ticket_kv($pdf, 'Fecha', $ctx['fechaSalida']);
    osb_ticket_kv($pdf, 'Cliente', ($ctx['clienteCodigo'] !== '' ? $ctx['clienteCodigo'] . ' · ' : '') . ($ctx['cliente'] !== '' ? $ctx['cliente'] : '-'));
    if ($ctx['contacto'] !== '' || $ctx['telefono'] !== '') osb_ticket_kv($pdf, 'Contacto', trim($ctx['contacto'] . ($ctx['telefono'] !== '' ? ' · ' . $ctx['telefono'] : '')));
    osb_ticket_kv($pdf, 'Solic.', ($ctx['fechaSolicitada'] !== '' ? $ctx['fechaSolicitada'] : '-') . ($ctx['horaSolicitada'] !== '' ? ' ' . $ctx['horaSolicitada'] : ''));
    osb_ticket_kv($pdf, 'Direc.', $ctx['direccion'] !== '' ? $ctx['direccion'] : '-');

    osb_ticket_section($pdf, 'Notas Ventas', $ctx['ventasNote']);
    osb_ticket_section($pdf, 'Notas Almacén', $ctx['almacenNote']);

    osb_ticket_line($pdf);
    $pdf->SetFont('Arial', 'B', 8);
    $pdf->Cell(0, 4.5, osb_text('Detalle por OC'), 0, 1, 'L');

    $totalPallets = 0.0;
    $totalPieces = 0.0;
    if (!$ctx['items']) {
        $pdf->SetFont('Arial', '', 7.5);
        $pdf->Cell(0, 4, osb_text('Sin artículos registrados'), 0, 1, 'L');
    } else {
        foreach ($ctx['items'] as $it) {
            $totalPallets += (float)$it['pallets_qty'];
            $totalPieces += (float)$it['total_pieces'];
            $pdf->SetFont('Arial', 'B', 7.5);
            $pdf->MultiCell(0, 4, osb_text('OC: ' . (string)$it['oc']), 0, 'L');
            $pdf->SetFont('Arial', '', 7.5);
            $pdf->MultiCell(0, 4, osb_text(trim((string)$it['sku'] . ' · ' . (string)$it['product_name'])), 0, 'L');
            $pdf->SetFont('Arial', '', 7);
            $pdf->Cell(24, 4, osb_text('Tar: ' . number_format((float)$it['pallets_qty'], 0, '.', ',')), 0, 0, 'L');
            $pdf->Cell(24, 4, osb_text('Pz/Paq: ' . number_format((float)$it['pieces_per_package'], 0, '.', ',')), 0, 0, 'L');
            $pdf->Cell(24, 4, osb_text('Pzas: ' . number_format((float)$it['total_pieces'], 0, '.', ',')), 0, 1, 'L');
            $pdf->Ln(1);
        }
    }

    osb_ticket_line($pdf);
    $pdf->SetFont('Arial', 'B', 8);
    $pdf->Cell(36, 5, osb_text('Total tarimas'), 0, 0, 'L');
    $pdf->Cell(0, 5, osb_text(number_format($totalPallets, 0, '.', ',')), 0, 1, 'R');
    $pdf->Cell(36, 5, osb_text('Total piezas'), 0, 0, 'L');
    $pdf->Cell(0, 5, osb_text(number_format($totalPieces, 0, '.', ',')), 0, 1, 'R');

    osb_ticket_line($pdf);
    $pdf->Ln(5);
    $pdf->SetFont('Arial', '', 7);
    $pdf->Cell(0, 4, osb_text('Recibe: ______________________________'), 0, 1, 'L');
    $pdf->Ln(7);
    $pdf->Cell(0, 4, osb_text('Entrega: _____________________________'), 0, 1, 'L');
    $pdf->Ln(2);
    $pdf->Cell(0, 4, osb_text('Fecha: ____/____/______'), 0, 1, 'L');

    return $pdf;
}

// ------------------------------------------------------------
// Autorización, igual de permisiva que el PDF original funcional.
// ------------------------------------------------------------
if (function_exists('ensure_session')) ensure_session();
$u = function_exists('current_user') ? current_user() : null;
if (!$u && function_exists('admin_user')) $u = admin_user();
if (!$u && session_status() === PHP_SESSION_NONE) @session_start();

$sessionUserId = 0;
foreach (['user_id', 'admin_user_id', 'uid', 'id_usuario', 'usuario_id'] as $sessionKey) {
    if (isset($_SESSION[$sessionKey]) && (int)$_SESSION[$sessionKey] > 0) { $sessionUserId = (int)$_SESSION[$sessionKey]; break; }
}
if (!$u && $sessionUserId <= 0) {
    http_response_code(403);
    echo 'No autorizado. Vuelve a iniciar sesión y genera nuevamente el PDF.';
    exit;
}
if (!class_exists('FPDF')) {
    http_response_code(500);
    echo 'La librería FPDF no está disponible.';
    exit;
}

$pdo = pdo();
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$scope = osb_scope();
$companyId = (int)$scope['company_id'];
$locationId = (int)$scope['location_id'];

$orderId = (int)($_GET['order_id'] ?? ($_GET['id'] ?? 0));
$outboundId = (int)($_GET['outbound_id'] ?? 0);
$folio = trim((string)($_GET['folio'] ?? ($_GET['reference'] ?? '')));

$order = osb_find_order($pdo, $orderId, $outboundId, $folio, $companyId, $locationId);
if (!$order) {
    http_response_code(404);
    echo 'Pedido no encontrado. Primero genera la salida desde Almacén.';
    exit;
}

$outbound = [];
if (!empty($order['outbound_id']) && osb_table_exists($pdo, 'outbounds')) {
    $st = $pdo->prepare("SELECT id AS outbound_id, outbound_date, reference, notes FROM outbounds WHERE id = ? LIMIT 1");
    $st->execute([(int)$order['outbound_id']]);
    $outbound = $st->fetch(PDO::FETCH_ASSOC) ?: [];
}

$items = osb_items($pdo, $order);
$folioVenta = osb_normalize_folio($order);
$folioSalida = trim((string)($outbound['reference'] ?? ''));
if ($folioSalida === '') $folioSalida = $folioVenta;

$cliente = trim((string)($order['business_name'] ?? ''));
$clienteCodigo = trim((string)($order['customer_code'] ?? ''));
$contacto = trim((string)($order['contact_name'] ?? ''));
$telefono = trim((string)($order['phone'] ?? ''));
$direccion = trim((string)($order['delivery_address'] ?? ''));
$fechaSolicitada = trim((string)($order['requested_delivery_date'] ?? ''));
$horaSolicitada = trim((string)($order['requested_delivery_time'] ?? ''));
$fechaSalida = trim((string)($outbound['outbound_date'] ?? ''));

$outboundNotes = (string)($outbound['notes'] ?? '');
$ventasNote = osb_extract_labeled_note($outboundNotes, 'Notas Ventas:');
if ($ventasNote === '') $ventasNote = trim((string)($order['delivery_instructions'] ?? ''));
if ($ventasNote === '') $ventasNote = osb_clean_note((string)($order['comments'] ?? ''));
$ventasNote = osb_clean_note($ventasNote);

$almacenNote = osb_extract_labeled_note($outboundNotes, 'Notas Almacén:');
if ($almacenNote === '') $almacenNote = osb_extract_labeled_note($outboundNotes, 'Notas Almacen:');
$almacenNote = osb_clean_note($almacenNote);

$ctx = [
    'items' => $items,
    'folioVenta' => $folioVenta,
    'folioSalida' => $folioSalida,
    'cliente' => $cliente,
    'clienteCodigo' => $clienteCodigo,
    'contacto' => $contacto,
    'telefono' => $telefono,
    'direccion' => $direccion,
    'fechaSolicitada' => $fechaSolicitada,
    'horaSolicitada' => $horaSolicitada,
    'fechaSalida' => $fechaSalida,
    'ventasNote' => $ventasNote,
    'almacenNote' => $almacenNote,
];

$format = osb_requested_format();
$pdf = $format === 'ticket' ? osb_render_ticket($ctx) : osb_render_carta($ctx);

$filenamePrefix = $format === 'ticket' ? 'ticket_salida_' : 'orden_salida_';
$filename = osb_safe_filename($filenamePrefix . $folioSalida) . '.pdf';

// Carta se descarga; ticket se abre inline para facilitar Ctrl+P / impresión térmica directa desde navegador.
$dest = $format === 'ticket' ? 'I' : 'D';
if (isset($_GET['download']) && (int)$_GET['download'] === 1) $dest = 'D';
if (isset($_GET['inline']) && (int)$_GET['inline'] === 1) $dest = 'I';

$pdf->Output($dest, $filename);
exit;
