<?php
declare(strict_types=1);
/**
 * modules/invoices/mark_paid.php
 *
 * Record or reset payments against an invoice:
 * - One-click full payment from view.php (no amount posted)
 * - Partial payment via form
 * - Mark Unpaid (reset)
 *
 * IMPORTANT:
 *   Per latest requirement, this file DOES NOT read/write the `pending_payments` table.
 *   Payments are reflected only on the invoice (paid_total/status) and optionally
 *   recorded in `invoice_payments` if that table exists.
 */

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'));

$iid = (int)($_GET['id'] ?? $_GET['invoice_id'] ?? $_POST['id'] ?? 0);
if ($iid <= 0) redirect(url_modules('invoices/list.php'));

$errors = [];
$notice = null;

/* Helpers */
function table_exists(string $t): bool {
  try {
    $q = db()->prepare("
      SELECT 1
        FROM INFORMATION_SCHEMA.TABLES
       WHERE TABLE_SCHEMA = DATABASE()
         AND TABLE_NAME   = :t
       LIMIT 1
    ");
    $q->execute([':t'=>$t]);
    return (bool)$q->fetchColumn();
  } catch(Throwable $e) { return false; }
}
function column_exists(string $table, string $c): bool {
  try {
    $q = db()->prepare("
      SELECT 1
        FROM INFORMATION_SCHEMA.COLUMNS
       WHERE TABLE_SCHEMA = DATABASE()
         AND TABLE_NAME   = :t
         AND COLUMN_NAME  = :c
       LIMIT 1
    ");
    $q->execute([':t'=>$table, ':c'=>$c]);
    return (bool)$q->fetchColumn();
  } catch(Throwable $e) { return false; }
}
function n2($v): string { return number_format((float)$v,2); }

/* Load invoice & balance */
$inv = db()->prepare("SELECT * FROM invoices WHERE id=:id AND company_id=:cid LIMIT 1");
$inv->execute([':id'=>$iid, ':cid'=>$cid]);
$invoice = $inv->fetch();
if (!$invoice) redirect(url_modules('invoices/list.php'));

$total   = (float)($invoice['total_amount'] ?? 0.00);
$paidTot = (float)($invoice['paid_total'] ?? 0.00);
$balance = max(0.0, $total - $paidTot);

/* POST actions */
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  try {
    csrf_verify((string)($_POST['csrf'] ?? ''));

    $action  = trim((string)($_POST['action'] ?? ''));
    $amount  = (float)($_POST['amount'] ?? 0);
    $paidAt  = trim((string)($_POST['paid_at'] ?? ''));
    $method  = trim((string)($_POST['method'] ?? ''));
    $ref     = trim((string)($_POST['reference'] ?? ''));
    $notes   = trim((string)($_POST['notes'] ?? ''));
    if ($paidAt === '') $paidAt = date('Y-m-d');

    if ($action === 'mark_unpaid') {
      db()->beginTransaction();
      $set = "paid_total = 0, status = 'draft'";
      if (column_exists('invoices','updated_at')) $set .= ", updated_at = NOW()";
      db()->prepare("UPDATE invoices SET {$set} WHERE id=:id AND company_id=:cid")->execute([':id'=>$iid, ':cid'=>$cid]);
      audit_log('invoice.mark_unpaid','invoice',$iid,[]);
      db()->commit();
      redirect(url_modules('invoices/view.php').'?id='.$iid.'&unpaid=1');
    }

    // Normal/partial payment flow
    db()->beginTransaction();

    // Lock & re-read invoice for accurate outstanding
    $re = db()->prepare("SELECT total_amount, paid_total, status FROM invoices WHERE id=:id AND company_id=:cid FOR UPDATE");
    $re->execute([':id'=>$iid, ':cid'=>$cid]);
    $row = $re->fetch();
    if (!$row) throw new RuntimeException('Invoice not found.');

    $curTotal = (float)$row['total_amount'];
    $curPaid  = (float)$row['paid_total'];
    $outstanding = max(0.0, $curTotal - $curPaid);

    // If no amount specified, assume "pay outstanding"
    if (($amount <= 0) && ($action === 'mark_paid' || $action === '')) {
      if ($outstanding <= 0) throw new RuntimeException('Nothing outstanding to pay.');
      $amount = $outstanding;
    }
    if ($amount <= 0) throw new RuntimeException('Payment amount must be greater than zero.');
    if ($amount > $outstanding + 0.0001) throw new RuntimeException('Amount exceeds outstanding.');

    // Save a payment record if invoice_payments table exists
    if (table_exists('invoice_payments')) {
      $ins = db()->prepare("
        INSERT INTO invoice_payments
          (company_id, invoice_id, paid_at, amount, method, reference, notes, created_at)
        VALUES
          (:cid, :iid, :paid_at, :amount, :method, :reference, :notes, NOW())
      ");
      $ins->execute([
        ':cid'=>$cid, ':iid'=>$iid, ':paid_at'=>$paidAt, ':amount'=>$amount,
        ':method'=>($method!==''?$method:null),
        ':reference'=>($ref!==''?$ref:null),
        ':notes'=>($notes!==''?$notes:null),
      ]);
    } else {
      // Fallback: append to invoice notes (non-blocking)
      $append = "\n[Payment ".date('Y-m-d H:i')."] £".number_format($amount,2)
              . ($method ? " via {$method}" : "")
              . ($ref ? " (Ref: {$ref})" : "")
              . ($notes ? " — {$notes}" : "");
      db()->prepare("UPDATE invoices SET notes = CONCAT(IFNULL(notes,''), :ap) WHERE id=:id AND company_id=:cid")
        ->execute([':ap'=>$append, ':id'=>$iid, ':cid'=>$cid]);
    }

    // Update invoice totals + status
    $newPaid = min($curTotal, $curPaid + $amount);
    $newStat = ($newPaid >= $curTotal && $curTotal > 0) ? 'paid' : (($newPaid > 0) ? 'partial' : ((string)$row['status'] ?: 'sent'));
    $set = "paid_total = :p, status = :s";
    if (column_exists('invoices','updated_at')) $set .= ", updated_at = NOW()";
    db()->prepare("UPDATE invoices SET {$set} WHERE id=:id AND company_id=:cid")->execute([
      ':p'=>$newPaid, ':s'=>$newStat, ':id'=>$iid, ':cid'=>$cid
    ]);

    // IMPORTANT: No writes to pending_payments here (per requirement)

    audit_log('invoice.mark_paid','invoice',$iid,[
      'amount'=>$amount,
      'new_paid_total'=>$newPaid,
      'new_status'=>$newStat,
      'method'=>$method,
      'reference'=>$ref
    ]);
    db()->commit();

    redirect(url_modules('invoices/view.php').'?id='.$iid.'&paid=1');

  } catch (Throwable $e) {
    if (db()->inTransaction()) db()->rollBack();
    $errors[] = (defined('APP_ENV') && APP_ENV==='dev') ? $e->getMessage() : 'Unable to update invoice.';
  }
}

/* GET form */
include dirname(__DIR__, 2) . '/includes/header.php';
$defAmount = $balance > 0 ? $balance : 0.00;
?>
<div class="d-flex justify-content-between align-items-center mb-3">
  <h1 class="h4 mb-0">Mark Invoice as Paid</h1>
  <div><a class="btn btn-outline-secondary" href="<?= e(url_modules('invoices/view.php').'?id='.$iid) ?>">Back to Invoice</a></div>
</div>

<?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; ?>

<div class="card shadow-sm">
  <div class="card-body">
    <?php
      // Recompute fresh summary for display (not locked)
      $re = db()->prepare("SELECT total_amount, paid_total, status FROM invoices WHERE id=:id AND company_id=:cid");
      $re->execute([':id'=>$iid, ':cid'=>$cid]);
      $r = $re->fetch() ?: [];
      $t = (float)($r['total_amount'] ?? $total);
      $p = (float)($r['paid_total'] ?? $paidTot);
      $b = max(0.0, $t - $p);
      $st= (string)($r['status'] ?? ($invoice['status'] ?? 'draft'));
    ?>
    <div class="row g-3 mb-3">
      <div class="col-md-3"><div class="p-2 border rounded bg-light"><div class="small text-muted">Total</div><div class="fw-bold">£ <?= e(n2($t)) ?></div></div></div>
      <div class="col-md-3"><div class="p-2 border rounded bg-light"><div class="small text-muted">Paid</div><div class="fw-bold">£ <?= e(n2($p)) ?></div></div></div>
      <div class="col-md-3"><div class="p-2 border rounded bg-light"><div class="small text-muted">Balance</div><div class="fw-bold">£ <?= e(n2($b)) ?></div></div></div>
      <div class="col-md-3"><div class="p-2 border rounded bg-light"><div class="small text-muted">Status</div><div class="fw-bold"><?= e(ucfirst($st)) ?></div></div></div>
    </div>

    <form method="post" class="row g-3">
      <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
      <input type="hidden" name="id" value="<?= (int)$iid ?>">
      <div class="col-md-3">
        <label class="form-label">Amount (£)</label>
        <input type="number" step="0.01" min="0.01" class="form-control" name="amount" value="<?= e((string)$defAmount) ?>">
        <div class="form-text">Leave as is to pay full outstanding.</div>
      </div>
      <div class="col-md-3">
        <label class="form-label">Paid At</label>
        <input type="date" class="form-control" name="paid_at" value="<?= e(date('Y-m-d')) ?>">
      </div>
      <div class="col-md-3">
        <label class="form-label">Method</label>
        <select name="method" class="form-select">
          <option value="">—</option><option>Bank Transfer</option><option>Card</option><option>Cash</option><option>Cheque</option><option>Other</option>
        </select>
      </div>
      <div class="col-md-3">
        <label class="form-label">Reference</label>
        <input class="form-control" name="reference" placeholder="e.g., TXN12345">
      </div>
      <div class="col-12">
        <label class="form-label">Notes</label>
        <textarea class="form-control" name="notes" rows="2" placeholder="Optional"></textarea>
      </div>
      <div class="col-12 d-flex gap-2">
        <button name="action" value="mark_paid" class="btn btn-dark">Save Payment</button>
        <a class="btn btn-outline-secondary" href="<?= e(url_modules('invoices/view.php').'?id='.$iid) ?>">Cancel</a>
      </div>
    </form>

    <hr class="my-4">

    <form method="post" class="d-inline" onsubmit="return confirm('Reset payments and mark this invoice as UNPAID (draft)?');">
      <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
      <input type="hidden" name="id" value="<?= (int)$iid ?>">
      <button name="action" value="mark_unpaid" class="btn btn-outline-danger">Mark Unpaid (Reset)</button>
    </form>
  </div>
</div>

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