<?php
/**
 * orden_entrega_pdf.php
 * ============================================================
 * Genera PDF de orden de entrega para el cliente.
 *
 * Flujo corregido:
 * - vh_dispatch primero guarda/sincroniza el pedido de VentasHielo
 *   en BReport sales_orders / sales_order_items.
 * - Luego crea outbounds / outbound_items / inventory_moves.
 * - Este PDF YA NO depende de consultar VentasHielo.
 * - No muestra costos ni importes.
 * - El folio visible se respeta desde sales_orders.sales_order_ref,
 *   por ejemplo PW-52, PW-86, etc.
 * ============================================================
 */

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 pdf_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 safe_pdf_filename(string $name): string {
    $name = preg_replace('/[^A-Za-z0-9_\-]/', '_', $name);
    $name = trim((string)$name, '_');
    return $name !== '' ? $name : 'orden_entrega';
}


/**
 * Las presentaciones comerciales de BReport se imprimen como piezas enteras.
 * El control transaccional de cantidades se realiza en Ventas / Almacén;
 * el PDF solo representa el movimiento ya registrado.
 */
function pdf_piece_qty($value): string {
    return number_format((float)$value, 0, '.', '');
}

/**
 * Calcula el número aproximado de líneas que usará MultiCell.
 * Trabaja con el texto ya convertido a ISO-8859-1 para usar la misma medida
 * que FPDF imprimirá realmente.
 */
function pdf_line_count(FPDF $pdf, string $text, float $width): int {
    $txt = pdf_text($text);
    if ($txt === '') return 1;

    $usable = max(1.0, $width - 4.0);
    $lines = 1;
    $buffer = '';

    $length = strlen($txt);
    for ($i = 0; $i < $length; $i++) {
        $char = $txt[$i];
        if ($char === "\n") {
            $lines++;
            $buffer = '';
            continue;
        }

        $candidate = $buffer . $char;
        if ($buffer !== '' && $pdf->GetStringWidth($candidate) > $usable) {
            $lines++;
            $buffer = $char;
        } else {
            $buffer = $candidate;
        }
    }

    return max(1, $lines);
}

function pdf_items_table_header(FPDF $pdf, array $widths): void {
    $pdf->SetFont('Arial', 'B', 10);
    $pdf->SetFillColor(242, 246, 251);
    $pdf->Cell($widths[0], 8, pdf_text('Cantidad'), 1, 0, 'C', true);
    $pdf->Cell($widths[1], 8, pdf_text('SKU'), 1, 0, 'C', true);
    $pdf->Cell($widths[2], 8, pdf_text('Producto'), 1, 1, 'C', true);
}

/**
 * Fila de tabla con altura dinámica. Evita que SKU y producto se encimen
 * usando MultiCell dentro de cada columna y dibujando el borde completo.
 */
function pdf_items_table_row(FPDF $pdf, array $widths, array $values): void {
    $lineHeight = 5.5;
    $maxLines = 1;
    foreach ($values as $index => $value) {
        $maxLines = max($maxLines, pdf_line_count($pdf, (string)$value, (float)$widths[$index]));
    }

    $rowHeight = max(8.0, ($maxLines * $lineHeight) + 3.0);

    // Letter con margen inferior seguro para firma y salto de página.
    if ($pdf->GetY() + $rowHeight > 255) {
        $pdf->AddPage();
        pdf_items_table_header($pdf, $widths);
    }

    /*
     * Se conserva la X inicial de la fila para regresar al inicio al terminar.
     * No se accede directamente a la propiedad interna del margen porque
     * en FPDF puede ser protegida y causar error fatal HTTP 500 en ejecución.
     */
    $startX = $pdf->GetX();
    $x = $startX;
    $y = $pdf->GetY();
    $alignments = ['C', 'L', 'L'];

    $pdf->SetFont('Arial', '', 10);
    foreach ($values as $index => $value) {
        $width = (float)$widths[$index];
        $pdf->Rect($x, $y, $width, $rowHeight);
        $pdf->SetXY($x + 1.5, $y + 1.5);
        $pdf->MultiCell($width - 3.0, $lineHeight, pdf_text((string)$value), 0, $alignments[$index]);
        $x += $width;
    }

    $pdf->SetXY($startX, $y + $rowHeight);
}

function pdf_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 pdf_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 pdf_get_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 pdf_normalize_folio(array $order): string {
    $folio = trim((string)($order['sales_order_ref'] ?? ''));
    if ($folio !== '') return $folio;

    $id = (int)($order['id'] ?? 0);
    return $id > 0 ? ('PW-' . $id) : 'PW';
}

function pdf_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;
    }

    $sql = "
        SELECT
            o.*,
            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;
}

// ------------------------------------------------------------
// Autorización para descarga de PDF
// ------------------------------------------------------------
// Permite cualquier sesión válida de BReport.
// La seguridad del documento se conserva con la búsqueda por scope.
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 = pdf_get_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 = pdf_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;
}

$itemsSql = "
    SELECT
        i.qty,
        p.sku,
        p.name AS product_name,
        p.uom
    FROM sales_order_items i
    JOIN products p ON p.id = i.product_id
    WHERE i.order_id = ?
    ORDER BY p.sku, p.name
";
$st = $pdo->prepare($itemsSql);
$st->execute([(int)$order['id']]);
$items = $st->fetchAll(PDO::FETCH_ASSOC);

$outbound = [];
if (!empty($order['outbound_id']) && pdf_table_exists($pdo, 'outbounds')) {
    $st = $pdo->prepare("
        SELECT
            ob.id AS outbound_id,
            ob.outbound_date,
            ob.reference,
            ob.notes,
            oc.name AS channel_name
        FROM outbounds ob
        LEFT JOIN outbound_channels oc ON oc.id = ob.channel_id
        WHERE ob.id = ?
        LIMIT 1
    ");
    $st->execute([(int)$order['outbound_id']]);
    $outbound = $st->fetch(PDO::FETCH_ASSOC) ?: [];
}

$folioMostrar = pdf_normalize_folio($order);
$cliente = trim((string)($order['business_name'] ?? ''));
$contacto = trim((string)($order['contact_name'] ?? ''));
$telefono = trim((string)($order['phone'] ?? ''));

$pdf = new FPDF('P', 'mm', 'Letter');
$pdf->AddPage();

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

$pdf->SetY(22);
$pdf->SetFont('Arial', 'B', 14);
$pdf->Cell(0, 8, pdf_text('Orden de entrega'), 0, 1, 'C');
$pdf->Ln(2);

$pdf->SetFont('Arial', '', 11);
$pdf->Cell(0, 6, pdf_text('Pedido BReport #' . (int)$order['id']), 0, 1);
$pdf->Cell(0, 6, pdf_text('Orden de compra / Folio: ' . $folioMostrar), 0, 1);
$pdf->Cell(0, 6, pdf_text('Cliente: ' . ($cliente !== '' ? $cliente : '-')), 0, 1);

if ($contacto !== '' || $telefono !== '') {
    $pdf->Cell(0, 6, pdf_text('Contacto: ' . ($contacto !== '' ? $contacto : '-') . ($telefono !== '' ? ' (' . $telefono . ')' : '')), 0, 1);
}

$direccion = trim((string)($order['delivery_address'] ?? ''));
$pdf->Cell(0, 6, pdf_text('Dirección: ' . ($direccion !== '' ? $direccion : '-')), 0, 1);
$pdf->Cell(0, 6, pdf_text('Fecha solicitada: ' . ((string)($order['requested_delivery_date'] ?? '') ?: '-')), 0, 1);

if (!empty($order['requested_delivery_time'])) {
    $pdf->Cell(0, 6, pdf_text('Hora solicitada: ' . (string)$order['requested_delivery_time']), 0, 1);
}

if (!empty($outbound['outbound_date'])) {
    $pdf->Cell(0, 6, pdf_text('Fecha surtido: ' . (string)$outbound['outbound_date']), 0, 1);
}
if (!empty($outbound['reference'])) {
    $pdf->Cell(0, 6, pdf_text('Referencia salida: ' . (string)$outbound['reference']), 0, 1);
}
if (!empty($outbound['channel_name'])) {
    $pdf->Cell(0, 6, pdf_text('Canal: ' . (string)$outbound['channel_name']), 0, 1);
}

$pdf->Ln(4);

if (!empty($order['comments'])) {
    $pdf->SetFont('Arial', 'B', 11);
    $pdf->Cell(0, 6, pdf_text('Comentarios / instrucciones:'), 0, 1);
    $pdf->SetFont('Arial', '', 11);
    $pdf->MultiCell(0, 6, pdf_text((string)$order['comments']));
    $pdf->Ln(2);
}

if (!empty($outbound['notes'])) {
    $pdf->SetFont('Arial', 'B', 11);
    $pdf->Cell(0, 6, pdf_text('Notas de salida:'), 0, 1);
    $pdf->SetFont('Arial', '', 11);
    $pdf->MultiCell(0, 6, pdf_text((string)$outbound['notes']));
    $pdf->Ln(2);
}

/*
 * Tabla de artículos con columnas balanceadas y salto de línea automático.
 * Ancho útil Letter con márgenes FPDF por defecto: 196 mm.
 */
$itemColumnWidths = [25, 62, 109];
pdf_items_table_header($pdf, $itemColumnWidths);

if (!$items) {
    pdf_items_table_row($pdf, $itemColumnWidths, ['-', '-', 'Sin artículos registrados']);
} else {
    foreach ($items as $it) {
        $qtyValue = pdf_piece_qty($it['qty'] ?? 0);
        $sku = (string)($it['sku'] ?? '');
        $name = (string)($it['product_name'] ?? '');
        pdf_items_table_row($pdf, $itemColumnWidths, [$qtyValue, $sku, $name]);
    }
}

$pdf->Ln(10);
$pdf->Cell(0, 6, pdf_text('Nombre y Firma de quien recibe: ___________________________'), 0, 1);
$pdf->Ln(8);
$pdf->Cell(0, 6, pdf_text('Nombre y Firma de quien entrega: ___________________________ Fecha: ___/___/_____'), 0, 1);

$filename = safe_pdf_filename('orden_entrega_' . $folioMostrar) . '.pdf';
$pdf->Output('D', $filename);
exit;
