<?php
declare(strict_types=1);
/**
 * modules/invoices/generate_from_booking.php
 *
 * Create an invoice from a booking reference.
 * Parts:
 *  1) Bootstrap & guards
 *  2) Helpers (load booking, invoice number, default VAT)
 *  3) Actions: preview (load booking) / create (insert invoice + lines)
 *  4) Render: search form, preview form (live totals)
 */

///////////////////////////////////////////////////////////////
// 1) Bootstrap & guards
///////////////////////////////////////////////////////////////
require_once dirname(__DIR__, 2) . '/config/functions.php';
require_role(['Admin','Ops']);

$user = current_user();
$cid  = (int)($user['company_id'] ?? 0);
if ($cid <= 0) redirect(url_public('login.php'));

$errors = [];
$notice = null;
$preview = [];   // booking preview payload
$lines   = [];   // preview line items

///////////////////////////////////////////////////////////////
// 2) Helpers
///////////////////////////////////////////////////////////////

/** Load booking by ref or id for this company (strict). */
function load_booking_for_invoice(int $companyId, ?string $bookingRef, ?int $bookingId): ?array {
  if ($bookingId && $bookingId > 0) {
    $sql = "SELECT * FROM bookings WHERE id=:id AND company_id=:cid LIMIT 1";
    $stmt = db()->prepare($sql);
    $stmt->execute([':id'=>$bookingId, ':cid'=>$companyId]);
    $row = $stmt->fetch();
    return $row ?: null;
  }
  if ($bookingRef !== null && $bookingRef !== '') {
    $sql = "SELECT * FROM bookings WHERE booking_ref=:ref AND company_id=:cid LIMIT 1";
    $stmt = db()->prepare($sql);
    $stmt->execute([':ref'=>$bookingRef, ':cid'=>$companyId]);
    $row = $stmt->fetch();
    return $row ?: null;
  }
  return null;
}

/** Generate invoice number: INV-YYYYMMDD-### (per company per day). */
function gen_invoice_no(int $companyId): string {
  $d      = date('Y-m-d');
  $stamp  = date('Ymd');
  $prefix = "INV-{$stamp}-";
  $q = db()->prepare("
    SELECT invoice_no
      FROM invoices
     WHERE company_id=:cid
       AND invoice_date=:d
       AND invoice_no LIKE :pref
  ");
  $q->execute([':cid'=>$companyId, ':d'=>$d, ':pref'=>$prefix.'%']);
  $max = 0;
  while ($r = $q->fetch()) {
    $no = (string)$r['invoice_no'];
    $parts = explode('-', $no);
    $last = end($parts);
    if (ctype_digit($last)) $max = max($max, (int)$last);
  }
  return $prefix . str_pad((string)($max+1), 3, '0', STR_PAD_LEFT);
}

/** Default VAT rate (from settings if present). */
function default_vat_rate(int $companyId): float {
  try {
    $s = db()->prepare("SELECT value FROM settings WHERE company_id=:cid AND `key` IN ('invoice_vat_rate','vat_rate') ORDER BY `key`='invoice_vat_rate' DESC LIMIT 1");
    $s->execute([':cid'=>$companyId]);
    if ($row = $s->fetch()) {
      $v = (float)$row['value'];
      return $v >= 0 ? $v : 0.0;
    }
  } catch (Throwable $e) {}
  return 0.0;
}

/** Human description for booking line. */
function booking_line_description(array $b): string {
  $ref = (string)($b['booking_ref'] ?? '');
  $type = (string)($b['booking_type'] ?? 'Transfer');
  $when = trim(($b['pickup_date'] ?? '') . (empty($b['pickup_time']) ? '' : (' '.$b['pickup_time'])));
  $from = trim((string)($b['pickup_address'] ?? ''));
  $via  = trim((string)($b['via'] ?? ''));
  $to   = trim((string)($b['dropoff_address'] ?? ''));
  $parts = [];
  $parts[] = "Booking Ref {$ref}";
  $parts[] = $type === 'As Directed'
    ? "As Directed" . (!empty($b['hours']) ? " ({$b['hours']}h)" : "")
    : "Transfer";
  if ($when !== '') $parts[] = $when;
  $route = $from !== '' ? $from : '';
  if ($via !== '')  $route .= ($route ? ' → ' : '') . "Via: {$via}";
  if ($to !== '')   $route .= ($route ? ' → ' : '') . $to;
  if ($route !== '') $parts[] = $route;
  return implode(' — ', array_filter($parts));
}

///////////////////////////////////////////////////////////////
// 3) Actions
///////////////////////////////////////////////////////////////
$action = (string)($_POST['action'] ?? $_GET['action'] ?? '');

if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'preview') {
  try {
    csrf_verify((string)($_POST['csrf'] ?? ''));

    $booking_ref = trim((string)($_POST['booking_ref'] ?? ''));
    $booking_id  = (int)($_POST['booking_id'] ?? 0) ?: null;

    $b = load_booking_for_invoice($cid, $booking_ref, $booking_id);
    if (!$b) {
      $errors[] = 'Booking not found.';
    } else {
      // Prevent duplicate invoice for same booking
      $exist = db()->prepare("SELECT id FROM invoices WHERE company_id=:cid AND booking_id=:bid LIMIT 1");
      $exist->execute([':cid'=>$cid, ':bid'=>$b['id']]);
      if ($exist->fetch()) {
        $errors[] = 'An invoice already exists for this booking.';
      } else {
        $base   = (float)($b['total_client_price'] ?? 0);
        $extras = (float)($b['client_parking_fee'] ?? 0) + (float)($b['client_waiting_fee'] ?? 0);

        $lines = [];
        $lines[] = [
          'description' => booking_line_description($b),
          'quantity'    => 1,
          'unit_price'  => $base,
          'line_total'  => $base,
        ];
        if ($extras > 0) {
          $lines[] = [
            'description' => 'Client extras (parking/waiting)',
            'quantity'    => 1,
            'unit_price'  => $extras,
            'line_total'  => $extras,
          ];
        }

        $preview = [
          'booking'       => $b,
          'invoice_no'    => gen_invoice_no($cid),
          'invoice_date'  => date('Y-m-d'),
          'due_date'      => date('Y-m-d', strtotime('+14 days')),
          'discount'      => 0.00,
          'vat_rate'      => default_vat_rate($cid),
        ];
        $notice = 'Preview loaded. Review and click Create Invoice.';
      }
    }
  } catch (Throwable $e) {
    $errors[] = (defined('APP_ENV') && APP_ENV === 'dev') ? $e->getMessage() : 'Unable to load preview.';
  }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'create') {
  try {
    csrf_verify((string)($_POST['csrf'] ?? ''));

    // Booking identity must be present
    $bid = (int)($_POST['booking_id'] ?? 0);
    if ($bid <= 0) throw new RuntimeException('Missing booking reference.');

    // Re-load booking (authoritative source)
    $b = load_booking_for_invoice($cid, null, $bid);
    if (!$b) throw new RuntimeException('Booking not found.');

    // Prevent duplicates
    $exist = db()->prepare("SELECT id FROM invoices WHERE company_id=:cid AND booking_id=:bid LIMIT 1");
    $exist->execute([':cid'=>$cid, ':bid'=>$b['id']]);
    if ($exist->fetch()) throw new RuntimeException('An invoice already exists for this booking.');

    // Inputs
    $invoice_no   = trim((string)($_POST['invoice_no'] ?? ''));
    $invoice_date = trim((string)($_POST['invoice_date'] ?? date('Y-m-d')));
    $due_date     = trim((string)($_POST['due_date'] ?? date('Y-m-d', strtotime('+14 days'))));
    $discount     = (float)($_POST['discount_amount'] ?? 0);
    $vat_rate     = (float)($_POST['vat_rate'] ?? 0);
    $notes        = trim((string)($_POST['notes'] ?? ''));

    if ($invoice_no === '') $invoice_no = gen_invoice_no($cid);

    // Line reconstruction from POST (defensive)
    $desc = $_POST['desc'] ?? [];
    $qty  = $_POST['qty']  ?? [];
    $unit = $_POST['unit'] ?? [];
    $rows = [];
    $sub  = 0.0;
    $n    = max(count($desc), count($qty), count($unit));
    for ($i=0; $i<$n; $i++) {
      $d = isset($desc[$i]) ? trim((string)$desc[$i]) : '';
      $q = isset($qty[$i])  ? (int)$qty[$i] : 0;
      $u = isset($unit[$i]) ? (float)$unit[$i] : 0.00;
      if ($d === '' && $q===0 && $u==0.00) continue;
      if ($d === '' || $q <= 0) continue;
      $lt = $q * $u;
      $rows[] = ['description'=>$d, 'quantity'=>$q, 'unit_price'=>$u, 'line_total'=>$lt];
      $sub   += $lt;
    }
    if (!$rows) throw new RuntimeException('No line items to save.');

    $discount = max(0.0, $discount);
    $vat_rate = max(0.0, $vat_rate);
    $base     = max(0.0, $sub - $discount);
    $vat_amt  = round($base * ($vat_rate/100), 2);
    $grand    = round($base + $vat_amt, 2);

    // Bill-to from booking client
    $bill_name  = (string)($b['client_name'] ?? '');
    $bill_email = (string)($b['client_email'] ?? '');
    $bill_addr  = ''; // (optional, unknown from bookings)

    // Duplicate invoice_no guard
    $dup = db()->prepare("SELECT id FROM invoices WHERE company_id=:cid AND invoice_no=:no LIMIT 1");
    $dup->execute([':cid'=>$cid, ':no'=>$invoice_no]);
    if ($dup->fetch()) throw new RuntimeException('Invoice number already exists.');

    db()->beginTransaction();

    // Insert invoice
    $ins = db()->prepare("
      INSERT INTO invoices (
        company_id, invoice_no, booking_id,
        bill_to_name, bill_to_email, bill_to_address,
        invoice_date, due_date,
        subtotal_amount, discount_amount, vat_rate, vat_amount, total_amount,
        paid_total, status, notes, created_at, updated_at
      ) VALUES (
        :cid, :no, :bid,
        :bn, :be, :ba,
        :idate, :ddate,
        :sub, :disc, :vr, :va, :grand,
        0.00, 'draft', :notes, NOW(), NOW()
      )
    ");
    $ins->execute([
      ':cid'   => $cid,
      ':no'    => $invoice_no,
      ':bid'   => $b['id'],
      ':bn'    => $bill_name !== '' ? $bill_name : null,
      ':be'    => $bill_email !== '' ? $bill_email : null,
      ':ba'    => $bill_addr !== '' ? $bill_addr : null,
      ':idate' => $invoice_date,
      ':ddate' => $due_date,
      ':sub'   => $sub,
      ':disc'  => $discount,
      ':vr'    => $vat_rate,
      ':va'    => $vat_amt,
      ':grand' => $grand,
      ':notes' => ($notes !== '' ? $notes : ('From booking '.$b['booking_ref'])),
    ]);
    $iid = (int)db()->lastInsertId();

    // Insert lines
    $insL = db()->prepare("
      INSERT INTO invoice_lines (invoice_id, description, quantity, unit_price, line_total)
      VALUES (:iid, :d, :q, :u, :lt)
    ");
    foreach ($rows as $ln) {
      $insL->execute([
        ':iid' => $iid,
        ':d'   => $ln['description'],
        ':q'   => $ln['quantity'],
        ':u'   => $ln['unit_price'],
        ':lt'  => $ln['line_total'],
      ]);
    }

    db()->commit();
    audit_log('invoice.create_from_booking', 'invoice', $iid, ['booking_id'=>$b['id'], 'invoice_no'=>$invoice_no]);
    redirect(url_modules('invoices/view.php').'?id='.$iid);
  } catch (Throwable $e) {
    if (db()->inTransaction()) db()->rollBack();
    $errors[] = (defined('APP_ENV') && APP_ENV === 'dev') ? $e->getMessage() : 'Unable to create invoice.';
  }
}

///////////////////////////////////////////////////////////////
// Load a quick list of recent bookings for convenience
///////////////////////////////////////////////////////////////
$recent = [];
try {
  $rb = db()->prepare("
    SELECT id, booking_ref, client_name, pickup_date, pickup_time, pickup_address, dropoff_address, total_client_price
      FROM bookings
     WHERE company_id=:cid
     ORDER BY id DESC
     LIMIT 25
  ");
  $rb->execute([':cid'=>$cid]);
  $recent = $rb->fetchAll();
} catch (Throwable $e) {}

include dirname(__DIR__, 2) . '/includes/header.php';
?>
<div class="d-flex justify-content-between align-items-center mb-3">
  <h1 class="h4 mb-0">Invoice from Booking</h1>
  <div class="d-flex gap-2">
    <a href="<?= e(url_modules('invoices/add.php')) ?>" class="btn btn-outline-secondary">Manual Invoice</a>
    <a href="<?= e(url_modules('invoices/list.php')) ?>" class="btn btn-outline-secondary">Back</a>
  </div>
</div>

<?php if ($notice): ?><div class="alert alert-success"><?= e($notice) ?></div><?php endif; ?>
<?php if ($errors): ?>
  <div class="alert alert-danger"><ul class="mb-0"><?php foreach ($errors as $er) echo '<li>'.e($er).'</li>'; ?></ul></div>
<?php endif; ?>

<!-- Search / Select Booking -->
<div class="card shadow-sm mb-3">
  <div class="card-body">
    <form method="post" class="row g-2 align-items-end">
      <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
      <input type="hidden" name="action" value="preview">
      <div class="col-md-4">
        <label class="form-label">Booking Ref</label>
        <input class="form-control" name="booking_ref" placeholder="e.g. BHC-<?= e(date('dmY')) ?>-500" value="<?= e($_POST['booking_ref'] ?? $_GET['ref'] ?? '') ?>">
      </div>
      <div class="col-md-5">
        <label class="form-label">Or pick a recent booking</label>
        <select class="form-select" name="booking_id">
          <option value="">—</option>
          <?php foreach ($recent as $r): ?>
            <option value="<?= (int)$r['id'] ?>">
              <?= e(($r['booking_ref'] ?? '—')) ?> —
              <?= e(($r['client_name'] ?? 'Client')) ?> —
              <?= e(($r['pickup_date'] ?? '')) ?> <?= e(($r['pickup_time'] ?? '')) ?>
            </option>
          <?php endforeach; ?>
        </select>
      </div>
      <div class="col-md-3 d-grid">
        <button class="btn btn-primary">Preview Invoice</button>
      </div>
    </form>
  </div>
</div>

<?php if ($preview && !$errors): ?>
  <?php
    $b = $preview['booking'];
    // Build preview lines if we didn’t already (from POST:preview)
    if (!$lines) {
      $base   = (float)($b['total_client_price'] ?? 0);
      $extras = (float)($b['client_parking_fee'] ?? 0) + (float)($b['client_waiting_fee'] ?? 0);
      $lines[] = [
        'description' => booking_line_description($b),
        'quantity'    => 1,
        'unit_price'  => $base,
        'line_total'  => $base,
      ];
      if ($extras > 0) {
        $lines[] = [
          'description' => 'Client extras (parking/waiting)',
          'quantity'    => 1,
          'unit_price'  => $extras,
          'line_total'  => $extras,
        ];
      }
    }
    $sub = 0.0;
    foreach ($lines as $ln) $sub += (float)$ln['line_total'];
    $disc = (float)$preview['discount'];
    $vr   = (float)$preview['vat_rate'];
    $base = max(0.0, $sub - $disc);
    $vat  = round($base * ($vr/100), 2);
    $grand= round($base + $vat, 2);
  ?>

  <form method="post" id="createForm" autocomplete="off">
    <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
    <input type="hidden" name="action" value="create">
    <input type="hidden" name="booking_id" value="<?= (int)$b['id'] ?>">

    <div class="card shadow-sm mb-3">
      <div class="card-body">
        <div class="d-flex justify-content-between align-items-center">
          <h2 class="h6 mb-0">Preview</h2>
          <div class="d-flex gap-2">
            <button class="btn btn-dark">Create Invoice</button>
          </div>
        </div>
        <hr>

        <div class="row g-3">
          <div class="col-md-4">
            <label class="form-label">Invoice #</label>
            <input class="form-control" name="invoice_no" value="<?= e($preview['invoice_no']) ?>">
            <div class="form-text">Auto-suggested; you can edit.</div>
          </div>
          <div class="col-md-3">
            <label class="form-label">Invoice Date</label>
            <input type="date" class="form-control" name="invoice_date" value="<?= e($preview['invoice_date']) ?>">
          </div>
          <div class="col-md-3">
            <label class="form-label">Due Date</label>
            <input type="date" class="form-control" name="due_date" value="<?= e($preview['due_date']) ?>">
          </div>
          <div class="col-md-2">
            <label class="form-label">VAT %</label>
            <input type="number" step="0.01" min="0" class="form-control js-calc" name="vat_rate" value="<?= e((string)$preview['vat_rate']) ?>">
          </div>

          <div class="col-md-12">
            <label class="form-label">Client</label>
            <div class="form-control-plaintext">
              <?= e($b['client_name'] ?? '—') ?>
              <?php if (!empty($b['client_email'])): ?> • <?= e($b['client_email']) ?><?php endif; ?>
            </div>
          </div>
        </div>

        <hr>
        <div class="table-responsive">
          <table class="table align-middle" id="linesTable">
            <thead class="table-light">
              <tr>
                <th style="width:48px;">#</th>
                <th>Description</th>
                <th style="width:100px;" class="text-end">Qty</th>
                <th style="width:140px;" class="text-end">Unit £</th>
                <th style="width:140px;" class="text-end">Line Total £</th>
              </tr>
            </thead>
            <tbody>
              <?php foreach ($lines as $i => $ln): ?>
                <tr>
                  <td><?= (int)($i+1) ?></td>
                  <td>
                    <input class="form-control form-control-sm" name="desc[]" value="<?= e($ln['description']) ?>">
                  </td>
                  <td>
                    <input type="number" step="1" min="1" class="form-control form-control-sm text-end js-qty" name="qty[]" value="<?= e((string)$ln['quantity']) ?>">
                  </td>
                  <td>
                    <input type="number" step="0.01" min="0" class="form-control form-control-sm text-end js-unit" name="unit[]" value="<?= e(number_format((float)$ln['unit_price'], 2, '.', '')) ?>">
                  </td>
                  <td class="text-end"><span class="js-lt"><?= number_format((float)$ln['line_total'], 2) ?></span></td>
                </tr>
              <?php endforeach; ?>
            </tbody>
          </table>
        </div>

        <div class="row g-2">
          <div class="col-md-4">
            <label class="form-label">Discount (£)</label>
            <input type="number" step="0.01" min="0" class="form-control js-calc" name="discount_amount" value="<?= e(number_format((float)$disc, 2, '.', '')) ?>">
          </div>
          <div class="col-md-8 d-flex align-items-end">
            <div class="ms-auto" style="min-width:320px;">
              <div class="p-2 border rounded bg-light">
                <div class="d-flex justify-content-between small">
                  <div class="text-muted">Subtotal</div>
                  <div id="sumSub"><?= number_format($sub, 2) ?></div>
                </div>
                <div class="d-flex justify-content-between small">
                  <div class="text-muted">Discount</div>
                  <div id="sumDisc"><?= number_format($disc, 2) ?></div>
                </div>
                <div class="d-flex justify-content-between small">
                  <div class="text-muted">VAT</div>
                  <div id="sumVat"><?= number_format($vat, 2) ?></div>
                </div>
                <div class="d-flex justify-content-between fw-bold">
                  <div>Total Due</div>
                  <div id="sumGrand"><?= number_format($grand, 2) ?></div>
                </div>
              </div>
            </div>
          </div>
        </div>

        <hr>
        <label class="form-label">Notes</label>
        <textarea class="form-control" name="notes" rows="2" placeholder="Optional (e.g. PO number)"><?= e($_POST['notes'] ?? 'From booking '.$b['booking_ref']) ?></textarea>

        <div class="mt-3">
          <button class="btn btn-dark">Create Invoice</button>
          <a href="<?= e(url_modules('invoices/generate_from_booking.php')) ?>" class="btn btn-outline-secondary">Start Over</a>
        </div>
      </div>
    </div>
  </form>

  <script>
  (function(){
    const tbody = document.querySelector('#linesTable tbody');
    const vatEl = document.querySelector('input[name="vat_rate"]');
    const discEl= document.querySelector('input[name="discount_amount"]');
    const sumSub = document.getElementById('sumSub');
    const sumDisc= document.getElementById('sumDisc');
    const sumVat = document.getElementById('sumVat');
    const sumGrand=document.getElementById('sumGrand');

    function num(v){ const n=parseFloat(v); return isNaN(n)?0:n; }
    function recalc(){
      let sub = 0;
      [...tbody.rows].forEach(tr=>{
        const q = num(tr.querySelector('.js-qty').value);
        const u = num(tr.querySelector('.js-unit').value);
        const lt= q*u;
        tr.querySelector('.js-lt').textContent = lt.toFixed(2);
        sub += lt;
      });
      const disc = num(discEl.value);
      const vr   = num(vatEl.value);
      const base = Math.max(0, sub - disc);
      const vat  = base * (vr/100);
      const grand= base + vat;

      sumSub.textContent   = sub.toFixed(2);
      sumDisc.textContent  = disc.toFixed(2);
      sumVat.textContent   = vat.toFixed(2);
      sumGrand.textContent = grand.toFixed(2);
    }
    tbody.addEventListener('input', e=>{
      if (e.target.matches('.js-qty, .js-unit')) recalc();
    });
    [vatEl, discEl].forEach(el=>el.addEventListener('input', recalc));
  })();
  </script>
<?php endif; ?>

<?php include dirname(__DIR__, 2) . '/includes/footer.php'; ?>
