<?php
declare(strict_types=1);

/**
 * modules/accounts/expenses/upload.php
 *
 * Standalone, AJAX-safe receipt uploader for expense transactions.
 *
 * Usage (AJAX POST multipart/form-data):
 *  - file:           <input name="file">
 *  - csrf:           CSRF token
 *  - transaction_id: int (required for attaching)
 *  - target:         "primary" | "extra" (default "extra")
 *
 * Behavior:
 *  - Saves file to /public/uploads/expenses/
 *  - If target=primary and transactions.attachment_url exists → replaces old file
 *  - If target=extra and transaction_attachments exists → inserts new attachment row
 *  - Otherwise, just returns { ok:true, file_url:"uploads/expenses/..." } for caller to use.
 */

require_once dirname(__DIR__, 3) . '/config/functions.php';
require_role(['Accounts','MD','Admin','Management']);

$user = current_user();
$cid  = (int)($user['company_id'] ?? 0);
if ($cid <= 0) {
  http_response_code(401);
  exit('Unauthorized');
}

/* ----------------------- helpers ----------------------- */
function respond_json(int $code, array $payload): void {
  http_response_code($code);
  header('Content-Type: application/json; charset=utf-8');
  echo json_encode($payload);
  exit;
}

function ensure_dir(string $dir): void {
  if (!is_dir($dir)) @mkdir($dir, 0775, true);
}

function delete_public_file(string $rel): void {
  $abs = dirname(__DIR__, 3) . '/public/' . ltrim($rel, '/');
  if (is_file($abs)) @unlink($abs);
}

function table_exists(string $table): bool {
  try {
    $q = db()->query("SHOW TABLES LIKE " . db()->quote($table));
    return (bool)$q->fetchColumn();
  } catch (Throwable $e) { return false; }
}

function table_has_column(string $table, string $col): bool {
  try {
    $q = db()->prepare("SHOW COLUMNS FROM `$table` LIKE :c");
    $q->execute([':c'=>$col]);
    return (bool)$q->fetch();
  } catch (Throwable $e) { return false; }
}

/* ----------------------- GET → tiny HTML form (manual test) ----------------------- */
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
  include dirname(__DIR__, 3) . '/includes/header.php';
  ?>
  <div class="col-12 col-md-7 col-lg-6">
    <div class="card shadow-sm">
      <div class="card-body">
        <h1 class="h5 mb-3">Upload Expense Receipt (Standalone)</h1>
        <form method="post" enctype="multipart/form-data" class="row g-3">
          <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
          <div class="col-12">
            <label class="form-label">Transaction ID</label>
            <input type="number" class="form-control" name="transaction_id" required>
          </div>
          <div class="col-12">
            <label class="form-label">Attach As</label>
            <select name="target" class="form-select">
              <option value="extra">Extra Attachment</option>
              <option value="primary">Primary (replace)</option>
            </select>
          </div>
          <div class="col-12">
            <label class="form-label">File</label>
            <input type="file" class="form-control" name="file" required>
          </div>
          <div class="col-12">
            <button class="btn btn-dark">Upload</button>
            <a href="<?= e(url_modules('accounts/expenses/list.php')) ?>" class="btn btn-outline-secondary">Back to Expenses</a>
          </div>
        </form>
        <p class="small text-muted mt-3">This page also supports AJAX. POST multipart to this URL and you'll get JSON back.</p>
      </div>
    </div>
  </div>
  <?php
  include dirname(__DIR__, 3) . '/includes/footer.php';
  exit;
}

/* ----------------------- POST → upload & attach ----------------------- */
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
  respond_json(405, ['ok'=>false, 'error'=>'Method not allowed']);
}

try {
  csrf_verify((string)($_POST['csrf'] ?? ''));

  $transactionId = (int)($_POST['transaction_id'] ?? 0);
  $target        = strtolower((string)($_POST['target'] ?? 'extra')); // extra|primary
  if (!in_array($target, ['extra','primary'], true)) $target = 'extra';

  if (!isset($_FILES['file'])) {
    respond_json(400, ['ok'=>false, 'error'=>'No file uploaded.']);
  }
  $file = $_FILES['file'];
  if (!is_uploaded_file($file['tmp_name']) || $file['error'] !== UPLOAD_ERR_OK) {
    respond_json(400, ['ok'=>false, 'error'=>'Upload failed.']);
  }

  $uploadDirAbs  = dirname(__DIR__, 3) . '/public/uploads/expenses';
  $uploadDirRel  = 'uploads/expenses';
  ensure_dir($uploadDirAbs);

  // File name
  $ext  = strtolower(pathinfo((string)$file['name'], PATHINFO_EXTENSION));
  $safe = 'exp_'.$cid.'_'.date('Ymd_His').'_'.bin2hex(random_bytes(4)).($ext ? '.'.$ext : '');
  $destAbs = $uploadDirAbs . '/' . $safe;
  $destRel = $uploadDirRel . '/' . $safe;

  if (!move_uploaded_file($file['tmp_name'], $destAbs)) {
    respond_json(500, ['ok'=>false, 'error'=>'Could not move file.']);
  }

  // If no transaction_id, just return the uploaded URL
  if ($transactionId <= 0) {
    respond_json(200, [
      'ok'        => true,
      'file_url'  => $destRel,
      'attached'  => null,
      'message'   => 'Uploaded (not attached to a transaction).'
    ]);
  }

  // Load transaction to verify ownership & type
  $tx = null;
  $sel = db()->prepare("
    SELECT id, company_id, type, attachment_url
    FROM transactions
    WHERE id=:id AND company_id=:cid
    LIMIT 1
  ");
  $sel->execute([':id'=>$transactionId, ':cid'=>$cid]);
  $tx = $sel->fetch();

  if (!$tx) {
    // leave the file on disk, but tell the client it isn't attached
    respond_json(404, ['ok'=>false, 'error'=>'Transaction not found (file saved but not attached).', 'file_url'=>$destRel]);
  }
  if ((string)$tx['type'] !== 'expense') {
    respond_json(400, ['ok'=>false, 'error'=>'Only expense transactions can have receipts.', 'file_url'=>$destRel]);
  }

  $hasPrimaryCol = table_has_column('transactions','attachment_url');
  $hasAttTable   = table_exists('transaction_attachments');

  $attachedAs = null;
  $oldPrimary = $hasPrimaryCol ? (string)($tx['attachment_url'] ?? '') : '';

  if ($target === 'primary' && $hasPrimaryCol) {
    // Replace primary
    $upd = db()->prepare("UPDATE transactions SET attachment_url=:u, updated_at=NOW() WHERE id=:id AND company_id=:cid LIMIT 1");
    $upd->execute([':u'=>$destRel, ':id'=>$transactionId, ':cid'=>$cid]);
    $attachedAs = 'primary';
    if ($oldPrimary) delete_public_file($oldPrimary);

  } elseif ($target === 'extra' && $hasAttTable) {
    // Append extra
    $ins = db()->prepare("
      INSERT INTO transaction_attachments (company_id, transaction_id, file_url, uploaded_at)
      VALUES (:cid, :tid, :url, NOW())
    ");
    $ins->execute([':cid'=>$cid, ':tid'=>$transactionId, ':url'=>$destRel]);
    $attachedAs = 'extra';

  } else {
    // Fallback: cannot attach to DB — return URL so caller can store it someplace else
    $attachedAs = null;
  }

  audit_log('expense.upload', 'transaction', (int)$transactionId, [
    'target'=>$target, 'file'=>$destRel, 'attachedAs'=>$attachedAs
  ]);

  respond_json(200, [
    'ok'        => true,
    'file_url'  => $destRel,
    'attached'  => $attachedAs,
    'message'   => $attachedAs
      ? "Uploaded & attached as {$attachedAs}."
      : "Uploaded. DB attachment not available in current schema."
  ]);

} catch (Throwable $e) {
  $msg = (defined('APP_ENV') && APP_ENV === 'dev') ? $e->getMessage() : 'Upload error.';
  respond_json(500, ['ok'=>false, 'error'=>$msg]);
}
