<?php
declare(strict_types=1);

ini_set('memory_limit', '512M');
@set_time_limit(120);
ini_set('pcre.backtrack_limit', '10000000');
ini_set('pcre.recursion_limit', '10000000');

use Dompdf\Dompdf;
use Dompdf\Options;

require_once __DIR__ . '/../../../vendor/autoload.php';

global $db, $config;

$basePath = rtrim((string)($config['app']['base_path'] ?? ''), '/');
$mblId = (int)($_GET['master_bl_id'] ?? $_GET['mbl_id'] ?? $_GET['id'] ?? 0);

if (!function_exists('h')) {
    function h(?string $v): string {
        return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8');
    }
}
if (!function_exists('n2')) {
    function n2($v): string {
        return number_format((float)$v, 2);
    }
}
if (!function_exists('n3')) {
    function n3($v): string {
        return number_format((float)$v, 3);
    }
}
if (!function_exists('safe_utf8')) {
    function safe_utf8($value): string {
        $value = (string)$value;
        if ($value === '') return '';

        if (function_exists('mb_convert_encoding')) {
            $converted = @mb_convert_encoding($value, 'UTF-8', 'UTF-8, ISO-8859-1, Windows-1252');
            if (is_string($converted) && $converted !== '') {
                $value = $converted;
            }
        } else {
            $converted = @iconv('UTF-8', 'UTF-8//IGNORE', $value);
            if ($converted !== false) {
                $value = $converted;
            }
        }

        $value = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/u', '', $value) ?? '';
        return $value;
    }
}
if (!function_exists('normalize_spaces_manifest')) {
    function normalize_spaces_manifest(string $value): string {
        return preg_replace('/\s+/u', ' ', trim(safe_utf8($value))) ?? '';
    }
}
if (!function_exists('safe_filename_part_manifest')) {
    function safe_filename_part_manifest(string $value): string {
        $value = normalize_spaces_manifest($value);
        $value = preg_replace('/[\\\\\/:*?"<>|]+/u', '', $value) ?? '';
        $value = preg_replace('/\s+/u', ' ', $value) ?? '';
        $value = trim($value, " .-\t\n\r\0\x0B");
        return $value !== '' ? strtoupper($value) : 'NA';
    }
}
if (!function_exists('masterBlsHasManifestNoColumn')) {
    function masterBlsHasManifestNoColumn(PDO $db): bool {
        try {
            $stmt = $db->query("SHOW COLUMNS FROM master_bls LIKE 'manifest_no'");
            return (bool)$stmt->fetch(PDO::FETCH_ASSOC);
        } catch (Throwable $e) {
            return false;
        }
    }
}
if (!function_exists('manifest_sequence_for_year')) {
    function manifest_sequence_for_year(PDO $db, int $year, bool $hasManifestNoColumn): string {
        if (!$hasManifestNoColumn) {
            return '001';
        }

        try {
            $like = 'MNFST%/' . $year;
            $stmt = $db->prepare("
                SELECT manifest_no
                FROM master_bls
                WHERE manifest_no LIKE ?
                ORDER BY id DESC
            ");
            $stmt->execute([$like]);
            $rows = $stmt->fetchAll(PDO::FETCH_COLUMN);

            $max = 0;
            foreach ($rows as $manifestNo) {
                $manifestNo = safe_utf8((string)$manifestNo);
                if (preg_match('/^MNFST(\d{3,})\/' . preg_quote((string)$year, '/') . '$/', $manifestNo, $m)) {
                    $num = (int)$m[1];
                    if ($num > $max) {
                        $max = $num;
                    }
                }
            }

            return str_pad((string)($max + 1), 3, '0', STR_PAD_LEFT);
        } catch (Throwable $e) {
            return '001';
        }
    }
}

if ($mblId <= 0) {
    http_response_code(400);
    exit('Missing MBL reference.');
}

$stmt = $db->prepare("
    SELECT
        m.*,
        sl.name AS shipping_line_name,
        p1.name AS pol_name,
        p2.name AS pod_name
    FROM master_bls m
    LEFT JOIN shipping_lines sl ON sl.id = m.shipping_line_id
    LEFT JOIN ports p1 ON p1.id = m.pol_port_id
    LEFT JOIN ports p2 ON p2.id = m.pod_port_id
    WHERE m.id = ?
    LIMIT 1
");
$stmt->execute([$mblId]);
$m = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$m) {
    http_response_code(404);
    exit('MBL not found.');
}

foreach ($m as $k => $v) {
    if (!is_numeric($v) && $v !== null) {
        $m[$k] = safe_utf8((string)$v);
    }
}

$hbls = $db->prepare("
    SELECT
        h.hbl_no,
        h.goods_description,
        h.packages,
        h.gross_weight_kg,
        h.cbm,
        h.marks_numbers,
        h.cfs,
        c1.name AS consignee_name,
        c1.address AS consignee_address,
        c2.name AS billing_name,
        c2.address AS billing_address
    FROM house_bls h
    LEFT JOIN customers c1 ON c1.id = h.consignee_customer_id
    LEFT JOIN customers c2 ON c2.id = h.billing_party_customer_id
    WHERE h.master_bl_id = ?
    ORDER BY h.id ASC
");
$hbls->execute([$mblId]);
$rows = $hbls->fetchAll(PDO::FETCH_ASSOC);

foreach ($rows as &$row) {
    foreach ($row as $k => $v) {
        if (!is_numeric($v) && $v !== null) {
            $row[$k] = safe_utf8((string)$v);
        }
    }
}
unset($row);

$totalPackages = 0;
$totalWeight = 0.0;
$totalCbm = 0.0;

foreach ($rows as $r) {
    $totalPackages += (int)($r['packages'] ?? 0);
    $totalWeight += (float)($r['gross_weight_kg'] ?? 0);
    $totalCbm += (float)($r['cbm'] ?? 0);
}

$manifestDate = date('j \\T\\H F Y');
$cfsValue = trim((string)($rows[0]['cfs'] ?? ''));
if ($cfsValue === '') {
    $cfsValue = trim((string)($rows[0]['billing_name'] ?? $rows[0]['consignee_name'] ?? '—'));
}

$year = (int)date('Y');
$hasManifestNoColumn = masterBlsHasManifestNoColumn($db);
$manifestCode = 'MNFST001';

if ($hasManifestNoColumn) {
    $currentManifestNo = trim((string)($m['manifest_no'] ?? ''));

    if ($currentManifestNo !== '' && preg_match('/^MNFST(\d{3,})\/(\d{4})$/', $currentManifestNo, $mm)) {
        $serial = $mm[1];
        $yearFromNo = (int)$mm[2];

        if ($yearFromNo === $year) {
            $manifestCode = 'MNFST' . $serial;
        } else {
            $serial = manifest_sequence_for_year($db, $year, true);
            $manifestCode = 'MNFST' . $serial;
            $newManifestNo = $manifestCode . '/' . $year;

            try {
                $upd = $db->prepare("UPDATE master_bls SET manifest_no = ? WHERE id = ?");
                $upd->execute([$newManifestNo, $mblId]);
            } catch (Throwable $e) {
            }
        }
    } else {
        $serial = manifest_sequence_for_year($db, $year, true);
        $manifestCode = 'MNFST' . $serial;
        $newManifestNo = $manifestCode . '/' . $year;

        try {
            $upd = $db->prepare("UPDATE master_bls SET manifest_no = ? WHERE id = ?");
            $upd->execute([$newManifestNo, $mblId]);
        } catch (Throwable $e) {
        }
    }
}

$vesselVoyForFile = safe_filename_part_manifest(trim((string)($m['vessel_name'] ?? '') . ' ' . (string)($m['voyage_no'] ?? '')));
$containerForFile = safe_filename_part_manifest((string)($m['container_no'] ?? 'NA'));
$filename = $manifestCode . '-' . $year . '-' . $vesselVoyForFile . '-' . $containerForFile . '-HOUSE MANIFEST.pdf';

$bannerFsPath = rtrim((string)($_SERVER['DOCUMENT_ROOT'] ?? ''), '/\\') . $basePath . '/assets/wcs-banner2.png';
$bannerDataUri = '';
if (is_file($bannerFsPath)) {
    $imgData = @file_get_contents($bannerFsPath);
    if ($imgData !== false) {
        $mime = function_exists('mime_content_type') ? mime_content_type($bannerFsPath) : 'image/png';
        $bannerDataUri = 'data:' . $mime . ';base64,' . base64_encode($imgData);
    }
}

$rowsHtml = '';
if ($rows) {
    foreach ($rows as $r) {
        $packageLabel = ((int)($r['packages'] ?? 0)) . ' PACKAGE' . (((int)($r['packages'] ?? 0)) !== 1 ? 'S' : '');

        $rowsHtml .= '
        <tr class="data-row">
            <td class="small">' . nl2br(h((string)($r['hbl_no'] ?? '—'))) . '</td>
            <td class="small">' . h((string)($r['consignee_name'] ?? '')) . '<br>' . nl2br(h((string)($r['consignee_address'] ?? ''))) . '</td>
            <td class="small">' . nl2br(h((string)(trim((string)($r['marks_numbers'] ?? '')) !== '' ? $r['marks_numbers'] : 'NO MARKS'))) . '</td>
            <td class="small">' . nl2br(h((string)($r['goods_description'] ?? '—'))) . '</td>
            <td>' . h((string)$packageLabel) . '</td>
            <td class="num">' . h((string)n2($r['gross_weight_kg'] ?? 0)) . '</td>
            <td class="num">' . h((string)n3($r['cbm'] ?? 0)) . '</td>
        </tr>';
    }

    $rowsHtml .= '
        <tr class="totals-row">
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td>' . h((string)$totalPackages) . ' PACKAGES</td>
            <td class="num">' . h((string)n2($totalWeight)) . ' KGS</td>
            <td class="num">' . h((string)n3($totalCbm)) . ' CBM</td>
        </tr>';
} else {
    $rowsHtml = '
        <tr>
            <td colspan="7" style="text-align:center;">No HBL rows found for this MBL.</td>
        </tr>';
}

$bannerHtml = $bannerDataUri !== ''
    ? '<img src="' . $bannerDataUri . '" alt="WSC Banner">'
    : '';

$html = '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Manifest</title>
<style>
  @page {
    size: A4 landscape;
    margin: 8mm;
  }

  html, body {
    background: #fff;
    margin: 0;
    padding: 0;
  }

  body {
    color: #000;
    font-family: Arial, Helvetica, sans-serif;
    font-size: 12px;
  }

  table {
    border-collapse: collapse;
  }

  .page-frame {
    border: 1px solid #666;
    padding: 16px;
    box-sizing: border-box;
  }

  .header-block {
    page-break-inside: avoid;
    margin-bottom: 22px;
  }

  .topbar {
    width: 100%;
  }

  .topbar td {
    vertical-align: top;
  }

  .left-meta {
    width: 54%;
    padding-right: 18px;
  }

  .right-brand {
    width: 46%;
    text-align: right;
  }

  .meta-table {
    width: 100%;
    font-size: 13px;
  }

  .meta-table td {
    border: 1px solid #555;
    padding: 4px 8px;
    vertical-align: top;
  }

  .meta-table .k {
    width: 45%;
    font-weight: 700;
    text-transform: uppercase;
    background: #f5f5f5;
  }

  .brand-half {
    width: 100%;
  }

  .brand-half img {
    width: 100%;
    max-width: 430px;
    height: auto;
    display: inline-block;
  }

  .brand-address {
    width: 100%;
    max-width: 430px;
    margin-top: 8px;
    margin-left: auto;
    text-align: center;
    color: #e96f00;
    font-weight: 700;
    font-size: 13px;
    line-height: 1.35;
  }

  .manifest-table {
    width: 100%;
    font-size: 12px;
    page-break-inside: auto;
  }

  .manifest-table thead {
    display: table-header-group;
  }

  .manifest-table tbody {
    display: table-row-group;
  }

  .manifest-table tr {
    page-break-inside: avoid;
    page-break-after: auto;
  }

  .manifest-table th,
  .manifest-table td {
    border: 1px solid #333;
    padding: 6px 6px;
    vertical-align: top;
    word-wrap: break-word;
  }

  .manifest-table th {
    text-align: left;
    font-weight: 700;
    background: #f3f4f6;
  }

  .num {
    text-align: right;
    white-space: nowrap;
  }

  .totals-row td {
    font-weight: 700;
    background: #fafafa;
  }

  .small {
    font-size: 11px;
    line-height: 1.35;
  }
</style>
</head>
<body>
<div class="page-frame">
  <div class="header-block">
    <table class="topbar">
      <tr>
        <td class="left-meta">
          <table class="meta-table">
            <tr><td class="k">DATE</td><td>' . h((string)$manifestDate) . '</td></tr>
            <tr><td class="k">CFS</td><td>' . h((string)($cfsValue !== '' ? $cfsValue : '—')) . '</td></tr>
            <tr><td class="k">VESSEL</td><td>' . h((string)trim((string)($m['vessel_name'] ?? '') . ' ' . (string)($m['voyage_no'] ?? ''))) . '</td></tr>
            <tr><td class="k">CONTAINER</td><td>' . h((string)(trim((string)($m['container_no'] ?? '')) . (trim((string)($m['container_type'] ?? '')) !== '' ? ' : ' . trim((string)$m['container_type']) : ''))) . '</td></tr>
            <tr><td class="k">ETA</td><td>' . h((string)($m['eta_date'] ?? '—')) . '</td></tr>
            <tr><td class="k">MBL</td><td>' . h((string)($m['mbl_no'] ?? '—')) . '</td></tr>
            <tr><td class="k">LOADING / DISCHARGE PORT</td><td>' . h((string)trim((string)($m['pol_name'] ?? '') . ' / ' . (string)($m['pod_name'] ?? ''))) . '</td></tr>
            <tr><td class="k">SHIPPING LINE</td><td>' . h((string)($m['shipping_line_name'] ?? '—')) . '</td></tr>
          </table>
        </td>
        <td class="right-brand">
          <div class="brand-half">
            ' . $bannerHtml . '
            <div class="brand-address">
              <div>P O BOX 81194-80100</div>
              <div>NEW CANNON TOWERS 7TH FLOOR</div>
              <div>MOI AVENUE - MOMBASA KENYA</div>
            </div>
          </div>
        </td>
      </tr>
    </table>
  </div>

  <table class="manifest-table">
    <thead>
      <tr>
        <th style="width:14%;">HBL</th>
        <th style="width:18%;">CONSIGNEE</th>
        <th style="width:18%;">MARKS &amp; NUMBERS</th>
        <th style="width:26%;">CARGO DESCRIPTION</th>
        <th style="width:10%;">QUANTITY</th>
        <th style="width:7%;">WEIGHT<br>(KGS)</th>
        <th style="width:7%;">CBM<br>(M3)</th>
      </tr>
    </thead>
    <tbody>
      ' . $rowsHtml . '
    </tbody>
  </table>
</div>
</body>
</html>';

$options = new Options();
$options->set('isRemoteEnabled', true);
$options->set('isHtml5ParserEnabled', true);
$options->set('defaultFont', 'Arial');

$dompdf = new Dompdf($options);
$dompdf->loadHtml($html, 'UTF-8');
$dompdf->setPaper('A4', 'landscape');
$dompdf->render();

$pdfBytes = $dompdf->output();

while (ob_get_level() > 0) {
    @ob_end_clean();
}

header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . str_replace('"', '', $filename) . '"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: public');

echo $pdfBytes;
exit;