<?php
declare(strict_types=1);

/**
 * modules/payroll/staff/pay.php
 * Record a salary payment for a staff member.
 *
 * Period logic (monthly, anchor = salary_day):
 *   Payment date P in month M → period = [ anchor(M-1)  ..  anchor(M)-1 day ]
 *   Example: salary_day=6, P=2025-10-05 → 2025-09-06 .. 2025-10-05
 *
 * Writes:
 *  - staff_salaries (company_id, staff_id, pay_month, amount, paid_at, method, reference, notes)
 *  - transactions   (account_code='STAFF_SALARY', type='expense',
 *                    segment=<Rent|Chauffeur>, booking_id=NULL)
 *
 * Visible to: MD, Accounts, Admin
 */

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

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

$errors = [];
$notice = null;

$staffId   = (int)($_GET['staff_id'] ?? $_POST['staff_id'] ?? 0);
$returnUrl = (string)($_GET['return'] ?? $_POST['return'] ?? url_modules('payroll/staff/list.php'));

/** Helpers */
function segment_for_staff(?string $department): string {
  return (strtolower((string)$department) === 'rent') ? 'Rent' : 'Chauffeur';
}
function safe_anchor(int $year, int $month, int $day): DateTimeImmutable {
  $dt = new DateTimeImmutable(sprintf('%04d-%02d-01', $year, $month));
  $last = (int)$dt->format('t');
  $d = max(1, min($day, $last));
  return new DateTimeImmutable($dt->format('Y-m-') . sprintf('%02d', $d));
}
function prev_month_anchor(DateTimeImmutable $anchor, int $day): DateTimeImmutable {
  $pm = $anchor->modify('-1 month');
  $last = (int)$pm->format('t');
  $d = max(1, min($day, $last));
  return new DateTimeImmutable($pm->format('Y-m-') . sprintf('%02d', $d));
}

/** Load staff */
$staff = null;
if ($staffId > 0) {
  try {
    $q = db()->prepare("
      SELECT id, company_id, full_name, department, pay_cycle, salary_amount, salary_day
      FROM staff_members
      WHERE id = :id AND company_id = :cid
      LIMIT 1
    ");
    $q->execute([':id'=>$staffId, ':cid'=>$cid]);
    $staff = $q->fetch() ?: null;
  } catch (Throwable $e) {
    $errors[] = (defined('APP_ENV') && APP_ENV==='dev') ? $e->getMessage() : 'Unable to load staff.';
  }
}
if (!$staff) {
  $errors[] = 'Staff not found or access denied.';
}

$staffName   = (string)($staff['full_name'] ?? '—');
$department  = (string)($staff['department'] ?? 'Chauffeur');
$segment     = segment_for_staff($department);
$baseSalary  = (float)($staff['salary_amount'] ?? 0.0);
$salaryDay   = (int)($staff['salary_day'] ?? 25);
if ($salaryDay < 1) $salaryDay = 1;

// Paid-at defaults to “now” for preview; user can change it
$paidAtInput = $_POST['paid_at'] ?? date('Y-m-d\TH:i');
$paidAtObj   = new DateTimeImmutable(str_replace(' ', 'T', (string)$paidAtInput));

/** Compute monthly period based on paidAtObj and salaryDay */
$y = (int)$paidAtObj->format('Y');
$m = (int)$paidAtObj->format('m');
$anchorCur  = safe_anchor($y, $m, $salaryDay);           // current-month anchor (S)
$anchorPrev = prev_month_anchor($anchorCur, $salaryDay); // previous-month anchor (S)
$periodFrom = $anchorPrev->format('Y-m-d');              // inclusive
$periodTo   = $anchorCur->modify('-1 day')->format('Y-m-d'); // inclusive
$payMonth   = $anchorCur->format('Y-m');                 // stored label

// Pull advances within period + salaries already logged for this payMonth
$advInPeriod = 0.0;
$alreadyPaidThisPeriod = 0.0;
try {
  $a = db()->prepare("
    SELECT COALESCE(SUM(amount),0) FROM staff_advances
    WHERE company_id=:cid AND staff_id=:sid AND DATE(paid_at) BETWEEN :from AND :to
  ");
  $a->execute([':cid'=>$cid, ':sid'=>$staffId, ':from'=>$periodFrom, ':to'=>$periodTo]);
  $advInPeriod = (float)$a->fetchColumn();

  $s = db()->prepare("
    SELECT COALESCE(SUM(amount),0) FROM staff_salaries
    WHERE company_id=:cid AND staff_id=:sid AND pay_month = :pm
  ");
  $s->execute([':cid'=>$cid, ':sid'=>$staffId, ':pm'=>$payMonth]);
  $alreadyPaidThisPeriod = (float)$s->fetchColumn();
} catch (Throwable $e) { /* ok */ }

$maxPayThisPeriod = max(0.0, $baseSalary - $advInPeriod - $alreadyPaidThisPeriod);
$suggested        = $maxPayThisPeriod;

/** Handle POST save */
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !$errors) {
  try {
    csrf_verify((string)($_POST['csrf'] ?? ''));

    // Inputs (maybe changed)
    $paidAtInput = trim((string)($_POST['paid_at'] ?? ''));
    $paidAtObj   = $paidAtInput !== '' ? new DateTimeImmutable(str_replace(' ', 'T', $paidAtInput)) : new DateTimeImmutable();
    $paidAtSQL   = $paidAtObj->format('Y-m-d H:i:s');

    // Recompute period with new paid date
    $y = (int)$paidAtObj->format('Y');
    $m = (int)$paidAtObj->format('m');
    $anchorCur  = safe_anchor($y, $m, $salaryDay);
    $anchorPrev = prev_month_anchor($anchorCur, $salaryDay);
    $periodFrom = $anchorPrev->format('Y-m-d');
    $periodTo   = $anchorCur->modify('-1 day')->format('Y-m-d');
    $payMonth   = $anchorCur->format('Y-m');

    // Recompute caps
    $a = db()->prepare("
      SELECT COALESCE(SUM(amount),0) FROM staff_advances
      WHERE company_id=:cid AND staff_id=:sid AND DATE(paid_at) BETWEEN :from AND :to
    ");
    $a->execute([':cid'=>$cid, ':sid'=>$staffId, ':from'=>$periodFrom, ':to'=>$periodTo]);
    $advInPeriod = (float)$a->fetchColumn();

    $s = db()->prepare("
      SELECT COALESCE(SUM(amount),0) FROM staff_salaries
      WHERE company_id=:cid AND staff_id=:sid AND pay_month = :pm
    ");
    $s->execute([':cid'=>$cid, ':sid'=>$staffId, ':pm'=>$payMonth]);
    $alreadyPaidThisPeriod = (float)$s->fetchColumn();

    $amount = to_dec($_POST['amount'] ?? 0);
    $method = trim((string)($_POST['method'] ?? 'Bank Transfer'));
    $ref    = trim((string)($_POST['reference'] ?? ''));
    $notes  = trim((string)($_POST['notes'] ?? ''));

    if ($amount <= 0) throw new RuntimeException('Amount must be positive.');

    $maxPayThisPeriod = max(0.0, $baseSalary - $advInPeriod - $alreadyPaidThisPeriod);
    if ($amount - $maxPayThisPeriod > 0.00001) {
      throw new RuntimeException(
        'Amount exceeds this period’s remaining salary. '.
        '(Base £'.number_format($baseSalary,2).
        ' − Advances £'.number_format($advInPeriod,2).
        ' − Already paid £'.number_format($alreadyPaidThisPeriod,2).
        ' = £'.number_format($maxPayThisPeriod,2).')'
      );
    }

    $pdo = db();
    $pdo->beginTransaction();

    // 1) staff_salaries
    $ins = $pdo->prepare("
      INSERT INTO staff_salaries
        (company_id, staff_id, pay_month, amount, paid_at, method, reference, notes, created_at)
      VALUES
        (:cid, :sid, :pm, :amt, :paid_at, :method, :ref, :notes, NOW())
    ");
    $ins->execute([
      ':cid'     => $cid,
      ':sid'     => $staffId,
      ':pm'      => $payMonth,
      ':amt'     => $amount,
      ':paid_at' => $paidAtSQL,
      ':method'  => $method !== '' ? $method : null,
      ':ref'     => $ref !== '' ? $ref : null,
      ':notes'   => $notes !== '' ? $notes : null,
    ]);

    // 2) transactions — bind segment as :seg and explicitly as string
    $seg = segment_for_staff($department);
    $tx = $pdo->prepare("
      INSERT INTO transactions
        (company_id, date, account_code, segment, type, amount, booking_id, rental_id, invoice_id, reference, milestone, notes, attachment_url, created_at)
      VALUES
        (:cid, DATE(:paid_at), 'STAFF_SALARY', :seg, 'expense', :amt, NULL, NULL, NULL, :ref, NULL, :notes, NULL, NOW())
    ");
    $tx->bindValue(':cid',     $cid,           PDO::PARAM_INT);
    $tx->bindValue(':paid_at', $paidAtSQL,     PDO::PARAM_STR);
    $tx->bindValue(':seg',     (string)$seg,   PDO::PARAM_STR);
    $tx->bindValue(':amt',     $amount);
    $tx->bindValue(':ref',     ($ref!=='' ? $ref : ('Salary — '.$staffName.' — '.$payMonth)), PDO::PARAM_STR);
    $tx->bindValue(':notes',   ($notes!=='' ? $notes : null), $notes!=='' ? PDO::PARAM_STR : PDO::PARAM_NULL);
    $tx->execute();

    audit_log('payroll.salary.create', 'staff', (int)$staffId, [
      'amount'             => $amount,
      'pay_month'          => $payMonth,
      'period_start'       => $periodFrom,
      'period_end'         => $periodTo,
      'paid_at'            => $paidAtSQL,
      'segment'            => $seg,
      'method'             => $method,
      'reference'          => $ref,
      'advances_in_period' => $advInPeriod,
      'already_paid'       => $alreadyPaidThisPeriod
    ]);

    $pdo->commit();
    $redir = $returnUrl . (str_contains($returnUrl,'?') ? '&' : '?') . 'ok=1';
    redirect($redir);

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

include dirname(__DIR__, 3) . '/includes/header.php';
?>
<div class="d-flex justify-content-between align-items-center mb-3">
  <div>
    <h1 class="h4 mb-0">Record Salary</h1>
    <div class="text-muted">
      Staff: <?= e($staffName) ?> · Department: <?= e($department) ?>
    </div>
  </div>
  <div class="d-flex gap-2">
    <a class="btn btn-outline-secondary" href="<?= e($returnUrl) ?>">← Back</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="row g-3 mb-3">
  <div class="col-md-3">
    <div class="card shadow-sm h-100"><div class="card-body">
      <div class="small text-muted">Base Salary / Cycle</div>
      <div class="h5 mb-0">£<?= number_format($baseSalary, 2) ?></div>
    </div></div>
  </div>
  <div class="col-md-3">
    <div class="card shadow-sm h-100"><div class="card-body">
      <div class="small text-muted">Salary Period</div>
      <div class="h6 mb-0"><?= e(date('d M Y', strtotime($periodFrom))) ?> → <?= e(date('d M Y', strtotime($periodTo))) ?></div>
    </div></div>
  </div>
  <div class="col-md-3">
    <div class="card shadow-sm h-100"><div class="card-body">
      <div class="small text-muted">Advances (in period)</div>
      <div class="h5 mb-0">£<?= number_format($advInPeriod, 2) ?></div>
    </div></div>
  </div>
  <div class="col-md-3">
    <div class="card shadow-sm h-100"><div class="card-body">
      <div class="small text-muted">Paid This Period</div>
      <div class="h5 mb-0">£<?= number_format($alreadyPaidThisPeriod, 2) ?></div>
    </div></div>
  </div>
</div>

<?php
if ($advInPeriod > 0) {
  $class = ($advInPeriod >= $baseSalary) ? 'danger' : (($advInPeriod >= 0.5*$baseSalary) ? 'warning' : 'info');
  ?>
  <div class="alert alert-<?= e($class) ?>">
    <strong>Note:</strong>
    You have £<?= number_format($advInPeriod,2) ?> in advances during this salary period.
    Net available to pay is capped at £<?= number_format($maxPayThisPeriod,2) ?>.
  </div>
<?php } ?>

<form method="post" class="row g-3">
  <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
  <input type="hidden" name="staff_id" value="<?= (int)$staffId ?>">
  <input type="hidden" name="return" value="<?= e($returnUrl) ?>">

  <div class="col-md-4">
    <label class="form-label">Amount (£)</label>
    <input type="number"
           class="form-control"
           name="amount"
           step="0.01"
           min="0.01"
           max="<?= e(number_format($maxPayThisPeriod, 2, '.', '')) ?>"
           value="<?= e(number_format(max(0.01, $suggested), 2, '.', '')) ?>"
           required>
    <div class="form-text">
      Max this period: £<?= number_format($maxPayThisPeriod,2) ?> (Base − Advances − Already paid).
    </div>
  </div>

  <div class="col-md-4">
    <label class="form-label">Paid At</label>
    <input type="datetime-local" class="form-control" name="paid_at" value="<?= e($paidAtObj->format('Y-m-d\TH:i')) ?>">
    <div class="form-text">Changing the date recalculates the covered period.</div>
  </div>

  <div class="col-md-4">
    <label class="form-label">Method</label>
    <input class="form-control" name="method" value="Bank Transfer" placeholder="Bank Transfer / Cash / etc.">
  </div>

  <div class="col-md-6">
    <label class="form-label">Reference</label>
    <input class="form-control" name="reference" placeholder="Txn ID / internal note">
  </div>

  <div class="col-md-6">
    <label class="form-label">Notes (optional)</label>
    <input class="form-control" name="notes" placeholder="Any additional info">
  </div>

  <div class="col-12 d-flex gap-2">
    <button class="btn btn-dark">Save Salary</button>
    <a class="btn btn-outline-secondary" href="<?= e($returnUrl) ?>">Cancel</a>
  </div>
</form>

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