<?php
header('Content-Type: application/json; charset=UTF-8');

$text = trim($_POST['text'] ?? '');
if (!$text) { echo json_encode(['error' => 'No text provided']); exit; }

// Debug log
$logFile = __DIR__ . '/../debug.txt';
$firstLine = strtok($text, "\n");
file_put_contents($logFile,
    "=== " . date('Y-m-d H:i:s') . " ===\n" .
    "LENGTH: " . strlen($text) . "\n" .
    "TABS_L1: " . substr_count($firstLine, "\t") . "\n" .
    "LINE1: " . substr($firstLine, 0, 300) . "\n" .
    "LINE2: " . substr(explode("\n", $text)[1] ?? '', 0, 300) . "\n===\n\n",
    FILE_APPEND
);

echo json_encode(parseInvoice($text));

// ─────────────────────────────────────────────────────────────────────────────

function parseInvoice(string $raw): array
{
    $lines    = array_values(array_filter(preg_split('/\r?\n/', $raw), fn($l) => trim($l) !== ''));
    $tabCount = isset($lines[0]) ? substr_count($lines[0], "\t") : 0;

    // TSV (spreadsheet paste) — 5+ tab chars in first line
    if ($tabCount >= 5) {
        return parseTSV($lines);
    }
    return parseFreeText($raw);
}

// ─── TSV Parser (Google Sheets / Excel copy-paste) ────────────────────────────

function parseTSV(array $lines): array
{
    $d = emptyDoc();

    // Detect if first row is a header row (contains text keywords, not numbers/dates)
    $firstCols = explode("\t", $lines[0]);
    $isHeader  = !preg_match('/^\d/', trim($firstCols[0]));  // starts with a digit → data row

    if ($isHeader && count($lines) >= 2) {
        $headers = array_map(fn($h) => strtolower(trim($h)), $firstCols);
        $values  = explode("\t", $lines[1]);
    } else {
        // No header — try to parse by position using known column structure
        $headers = knownHeaders();
        $values  = $firstCols;
    }

    // Pad values to match headers count
    while (count($values) < count($headers)) $values[] = '';

    // Build header→value map
    $hv = [];
    foreach ($headers as $i => $h) {
        $hv[$h] = trim($values[$i] ?? '');
    }

    // ── Direct field mapping ──────────────────────────────────────────────────

    $get = function(array $keys) use ($hv): string {
        foreach ($keys as $k) {
            $k = strtolower(trim($k));
            if (!empty($hv[$k])) return $hv[$k];
        }
        return '';
    };

    $d['bill_to_name']     = $get(['customer','customer name','bill to','client']);
    $d['booking_number']   = $get(['booking','booking #','booking number','bkg']);
    $d['reference_number'] = $get(['customer reference','reference','ref #','ref','reference #']);
    $d['container']        = $get(['container','cntr']);
    $d['container_number'] = $d['container'];
    $d['size']             = $get(['container size','size','sz']);
    $d['type']             = $get(['container type','type','tp','container type']);
    $d['bol']              = $get(['bol','b/l','bill of lading']);
    $d['pickup_date']      = $get(['pick up','pick up date','pickup','pickup date']);
    $d['delivery_date']    = $get(['delivery','delivery date','del date']);
    $d['return_date']      = $get(['return','return date','ret date']);
    $d['invoice_number']   = $get(['invoice number','invoice #','inv #','invoice no']);
    $d['invoice_date']     = $get(['invoice date','date']);
    $d['due_date']         = $get(['invoice expiration date','due date','expiration date','exp date']);
    $d['notes']            = $get(['notes','comments','remarks']);

    // Origin from PORT columns
    $portName = $get(['port','origin','origin name','terminal']);
    $portAddr = $get(['port address','origin address','port addr']);
    $d['origin_name']  = $portName;
    splitAddress($portAddr, $d, 'origin');

    // Destination from SHIPPER/CONSIGNEE columns
    $destName = $get(['shipper/consignee','shipper consignee','consignee','destination','dest','deliver to']);
    $destAddr = $get(['shipper/consignee address','consignee address','nee address','destination address','dest address','dest addr']);
    $d['dest_name']  = $destName;
    splitAddress($destAddr, $d, 'dest');

    // Customer information block (address + phone for Bill To)
    $custInfo = $get(['customer information','customer info','bill to information']);
    if ($custInfo) {
        extractCustomerInfo($custInfo, $d);
    }

    // ── Service columns (QTY + AMOUNT pairs) ─────────────────────────────────

    $serviceNames = [
        'freight + fuel + 2 day chassis' => 'Freight + Fuel + 2 Day Chassis',
        'freight+fuel+2 day chassis'     => 'Freight + Fuel + 2 Day Chassis',
        'freight + fuel'                 => 'Freight + Fuel',
        'chassis'                        => 'Chassis',
        'storage'                        => 'Storage',
        'hazmat'                         => 'Hazmat',
        'local trip'                     => 'Local Trip',
        'pre pull'                       => 'Pre Pull',
        'port fees'                      => 'Port Fees',
        'port fee'                       => 'Port Fees',
        'admin fee'                      => 'Admin Fee',
        'admin'                          => 'Admin Fee',
        'lumper'                         => 'Lumper',
        'missed trip'                    => 'Missed Trip',
        'weekend fee'                    => 'Weekend Fee',
        'waiting time'                   => 'Waiting Time',
        'other'                          => 'Other',
    ];

    // Walk headers; when we find a service name, look for adjacent QUANTITY col
    $services = [];
    for ($i = 0; $i < count($headers); $i++) {
        $h     = $headers[$i];
        $label = $serviceNames[$h] ?? null;
        if (!$label) continue;

        $val = trim($values[$i] ?? '');
        $amt = (float) str_replace(['$', ',', ' '], '', $val);

        // Find nearest QUANTITY column (before or after)
        $qty = 1;
        if (isset($headers[$i - 1]) && strtolower(trim($headers[$i - 1])) === 'quantity') {
            $qty = (int)(trim($values[$i - 1] ?? 1));
        } elseif (isset($headers[$i + 1]) && strtolower(trim($headers[$i + 1])) === 'quantity') {
            $qty = (int)(trim($values[$i + 1] ?? 1));
        }

        if ($amt > 0) {
            $services[] = ['description' => $label, 'qty' => (string)$qty, 'amount' => $amt];
        }
    }

    if (!empty($services)) $d['services'] = $services;

    return $d;
}

// ─── Free-text Parser ─────────────────────────────────────────────────────────

function parseFreeText(string $raw): array
{
    $lines = preg_split('/\r?\n/', $raw);
    $d     = emptyDoc();

    // Key:Value scan
    $kv = [];
    foreach ($lines as $line) {
        if (preg_match('/^([^:]{1,50}):\s*(.+)$/', trim($line), $m)) {
            $kv[strtolower(trim($m[1]))] = trim($m[2]);
        }
    }

    $pick = function(array $keys) use ($kv): string {
        foreach ($keys as $k) {
            if (!empty($kv[strtolower($k)])) return $kv[strtolower($k)];
        }
        return '';
    };

    $d['invoice_number']   = $pick(['invoice #','invoice#','invoice no','invoice number','inv #','inv']);
    $d['invoice_date']     = $pick(['invoice date','date','inv date']);
    $d['due_date']         = $pick(['due date','due','payment due','invoice expiration date']);
    $d['container_number'] = $pick(['container #','container#','container number','container no','cntr #','cntr']);
    $d['booking_number']   = $pick(['booking #','booking#','booking number','booking','bkg #','bkg']);
    $d['reference_number'] = $pick(['reference #','reference#','reference number','ref #','ref','customer reference']);
    $d['bill_to_name']     = $pick(['bill to','bill to name','client','customer','to']);
    $d['bill_to_addr1']    = $pick(['bill to address 1','bill to address1','address 1','address1','addr1']);
    $d['bill_to_addr2']    = $pick(['bill to address 2','bill to address2','address 2','address2','addr2']);
    $d['bill_to_phone']    = $pick(['phone','ph','tel','bill to phone']);
    $d['container']        = $pick(['container','cntr']) ?: $d['container_number'];
    $d['size']             = $pick(['size','container size']);
    $d['type']             = $pick(['type','container type']);
    $d['bol']              = $pick(['bol','b/l','bill of lading']);
    $d['pickup_date']      = $pick(['pickup','pickup date','pick up','pick up date']);
    $d['delivery_date']    = $pick(['delivery','delivery date']);
    $d['return_date']      = $pick(['return','return date']);
    $d['origin_name']      = $pick(['origin','origin name','port','terminal','from']);
    $d['origin_addr1']     = $pick(['origin address 1','origin address','port address','from address']);
    $d['origin_addr2']     = $pick(['origin address 2','origin city']);
    $d['dest_name']        = $pick(['destination','destination name','dest','shipper/consignee','consignee','deliver to']);
    $d['dest_addr1']       = $pick(['destination address 1','destination address','dest address','consignee address']);
    $d['dest_addr2']       = $pick(['destination address 2','dest city']);
    $d['notes']            = $pick(['notes','comments','remarks']);

    // Container ISO auto-detect
    if (!$d['container_number'] && preg_match('/\b([A-Z]{4}\d{7})\b/', $raw, $m)) {
        $d['container_number'] = $m[1];
        if (!$d['container']) $d['container'] = $m[1];
    }

    // Dates near keywords
    $dateNear = function(string $kw) use ($raw): string {
        if (preg_match('/' . preg_quote($kw, '/') . '\W{0,20}(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4})/i', $raw, $m))
            return $m[1];
        return '';
    };
    if (!$d['pickup_date'])   $d['pickup_date']   = $dateNear('pickup');
    if (!$d['delivery_date']) $d['delivery_date'] = $dateNear('delivery');
    if (!$d['return_date'])   $d['return_date']   = $dateNear('return');

    // Phone
    if (!$d['bill_to_phone'] && preg_match('/(?:\+1\s*)?\(?\d{3}\)?[\s.\-]\d{3}[\s.\-]\d{4}/', $raw, $m))
        $d['bill_to_phone'] = $m[0];

    // Bill To block
    if (!$d['bill_to_name'] && preg_match('/bill\s+to\s*\n\s*(.+)/i', $raw, $m))
        $d['bill_to_name'] = trim($m[1]);

    // Address heuristics
    if (!$d['bill_to_addr1'] && preg_match('/\b\d+\s+\w.+(?:st|ave|rd|blvd|dr|ln|way|ct|pkwy|hwy|street|avenue|road)\b/i', $raw, $m))
        $d['bill_to_addr1'] = trim($m[0]);
    if (!$d['bill_to_addr2'] && preg_match('/\b[A-Za-z\s]+,\s*[A-Z]{2}\s*\d{5}\b/', $raw, $m))
        $d['bill_to_addr2'] = trim($m[0]);

    // Services (lines ending in amount)
    $services = [];
    foreach ($lines as $line) {
        $line = trim($line);
        if (preg_match('/^(.+?)\s+(\d+)\s+\$?([\d,]+\.?\d{0,2})\s*$/', $line, $m)) {
            $amt = (float)str_replace(',', '', $m[3]);
            if ($amt > 0) {
                $services[] = ['description' => trim($m[1]), 'qty' => $m[2], 'amount' => $amt];
                continue;
            }
        }
        if (preg_match('/^(.+?)\s+\$?([\d,]+\.\d{2})\s*$/', $line, $m)) {
            $amt = (float)str_replace(',', '', $m[2]);
            if ($amt > 0 && !preg_match('/^(total|subtotal|due|amount|balance|invoice)/i', $m[1])) {
                $services[] = ['description' => trim($m[1]), 'qty' => '1', 'amount' => $amt];
            }
        }
    }
    if (!empty($services)) $d['services'] = $services;

    return $d;
}

// ─── Helpers ──────────────────────────────────────────────────────────────────

function emptyDoc(): array {
    return [
        'invoice_number'=>'','invoice_date'=>'','due_date'=>'',
        'container_number'=>'','booking_number'=>'','reference_number'=>'',
        'bill_to_name'=>'','bill_to_addr1'=>'','bill_to_addr2'=>'','bill_to_phone'=>'',
        'container'=>'','size'=>'','type'=>'',
        'bol'=>'','pickup_date'=>'','delivery_date'=>'','return_date'=>'',
        'origin_name'=>'','origin_addr1'=>'','origin_addr2'=>'',
        'dest_name'=>'','dest_addr1'=>'','dest_addr2'=>'',
        'notes'=>'', 'services'=>[],
    ];
}

// Split "4100 McIntosh Rd., Port Everglades, FL 33316" into addr1 + addr2
function splitAddress(string $addr, array &$d, string $prefix): void
{
    if (!$addr) return;
    // city,state zip at the end
    if (preg_match('/^(.*?),?\s*([A-Za-z\s]+,\s*[A-Z]{2}\s*\d{5}.*)$/s', $addr, $m)) {
        $d[$prefix . '_addr1'] = trim($m[1]);
        $d[$prefix . '_addr2'] = trim($m[2]);
    } else {
        // Try splitting on last comma
        $parts = array_map('trim', explode(',', $addr));
        if (count($parts) >= 2) {
            $d[$prefix . '_addr2'] = array_pop($parts);
            $d[$prefix . '_addr1'] = implode(', ', $parts);
        } else {
            $d[$prefix . '_addr1'] = $addr;
        }
    }
}

// Parse customer info blob: "7270 NW 35th Terrace, Suite 602, MIAMI, FL 33122, Phone: ..."
function extractCustomerInfo(string $info, array &$d): void
{
    // Phone
    if (!$d['bill_to_phone'] && preg_match('/(?:phone|ph|tel)[\s:]*(\+?[\d\s().+-]{7,20})/i', $info, $m))
        $d['bill_to_phone'] = trim($m[1]);

    // Strip phone + federal tax id lines
    $clean = preg_replace('/,?\s*(?:phone|ph|tel|federal tax id|tax id)[^,\n]*/i', '', $info);
    $clean = trim($clean, " ,\n\r");
    splitAddress($clean, $d, 'bill_to');
}

// Known column order when headers not pasted (positional fallback)
function knownHeaders(): array
{
    return [
        'customer','customer information','pick up','delivery','return',
        'port','port address','shipper/consignee','shipper/consignee address',
        'container','booking','customer reference','container size','container type','bol',
        'quantity','freight + fuel + 2 day chassis',
        'quantity','chassis',
        'quantity','storage',
        'quantity','hazmat',
        'quantity','local trip',
        'quantity','pre pull',
        'quantity','port fees',
        'quantity','admin fee',
        'quantity','lumper',
        'quantity','missed trip',
        'quantity','weekend fee',
        'quantity','waiting time',
        'quantity','other',
        'discount','discount reason',
        'invoice amount','invoice number','invoice date','invoice expiration date','notes',
    ];
}
