<?php
declare(strict_types=1);

/**
 * modules/payroll/staff/pay.php
 * Record a salary payment for a staff member.
 *
 * Two-step flow (like advance.php):
 *  - Step 1: If no staff_id -> show dropdown to select staff.
 *  - Step 2: With staff_id -> compute anchored period, enforce caps, save.
 *
 * Period logic (monthly):
 *   - Uses staff_members.salary_day as anchor S.
 *   - For any chosen paid_at date P in a month, the covered period is:
 *       [ anchor(S) of previous month  ...  (anchor(S) of current month - 1 day) ]
 *     Example: S=6, P in October => period = 06-Sep .. 05-Oct, pay_month label = 2025-10.
 *
 * Writes:
 *  - staff_salaries (company_id, staff_id, pay_month, amount, paid_at, method, reference, notes, created_at)
 *  - transactions   (account_code='STAFF_SALARY', type='expense',
 *                    segment=<Rent|Chauffeur>, booking_id=NULL, reference, notes, created_at)
 *
 * 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;

/** Helpers */
function segment_for_staff(?string $department): string {
  // EXACTLY match your enum('Rent','Chauffeur')
  return (strtolower((string)$department) === 'rent') ? 'Rent' : 'Chauffeur';
}
function safe_anchor(int $year, int $month, int $day): DateTimeImmutable {
  // Normalize to the given month (supports out-of-range months), clamp day to last day
  $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));
}

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

/** Step 1: if selector form submitted, update staffId */
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'select_staff') {
  $staffId = (int)($_POST['staff_id'] ?? 0);
}

/** Load active staff list for dropdown */
$staffList = [];
try {
  $q = db()->prepare("
    SELECT id, full_name, department
      FROM staff_members
     WHERE company_id = :cid AND is_active = 1
     ORDER BY full_name ASC
  ");
  $q->execute([':cid' => $cid]);
  $staffList = $q->fetchAll() ?: [];
} catch (Throwable $e) {
  $errors[] = (defined('APP_ENV') && APP_ENV==='dev') ? $e->getMessage() : 'Unable to load staff list.';
}

/** If we have a staffId, load staff row for details (Step 2) */
$staff      = null;
$staffName  = '—';
$department = 'Chauffeur';
$salaryDay  = 25;
$baseSalary = 0.0;

if ($staffId > 0) {
  try {
    $s = 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
    ");
    $s->execute([':id' => $staffId, ':cid' => $cid]);
    $staff = $s->fetch() ?: null;

    if ($staff) {
      $staffName  = (string)$staff['full_name'];
      $department = (string)($staff['department'] ?? 'Chauffeur');
      $salaryDay  = (int)($staff['salary_day'] ?? 25);
      if ($salaryDay <= 0 || $salaryDay > 31) $salaryDay = 25;
      $baseSalary = (float)($staff['salary_amount'] ?? 0.0);
    } else {
      $errors[] = 'Staff not found or access denied.';
    }
  } catch (Throwable $e) {
    $errors[] = (defined('APP_ENV') && APP_ENV==='dev') ? $e->getMessage() : 'Unable to load staff.';
  }
}

/** Determine paid_at default and compute anchored period (only when staff loaded) */
$paidAtInput = $_POST['paid_at'] ?? date('Y-m-d\TH:i');
$paidAtObj   = new DateTimeImmutable(str_replace(' ', 'T', (string)$paidAtInput));

$periodFrom = $periodTo = $payMonth = '';
$advInPeriod = 0.0;
$alreadyPaidThisPeriod = 0.0;
$maxPayThisPeriod = 0.0;
$suggested = 0.0;

if ($staff) {
  $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');                 // label stored in staff_salaries

  // Pull advances inside the anchored period + salaries already logged for this payMonth
  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) { /* keep zeros */ }

  // Net cap = Base − Advances − Already paid for this anchored period
  $maxPayThisPeriod = max(0.0, $baseSalary - $advInPeriod - $alreadyPaidThisPeriod);
  $suggested        = $maxPayThisPeriod;
}

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

    // Re-read inputs (user may alter paid_at)
    $amount = to_dec($_POST['amount'] ?? 0);
    $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');

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

    // Recompute anchored period using the possibly new paidAt 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');

    // Fresh sums for this exact anchored period
    $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();

    $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, // YYYY-MM label for the anchored period
      ':amt'     => $amount,
      ':paid_at' => $paidAtSQL,
      ':method'  => $method !== '' ? $method : null,
      ':ref'     => $ref !== '' ? $ref : null,
      ':notes'   => $notes !== '' ? $notes : null,
    ]);

    // 2) transactions — segment is ALWAYS set from staff department
    $segment = segment_for_staff($department); // 'Rent' or 'Chauffeur'
    $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', :segment, 'expense', :amt, NULL, NULL, NULL, :ref, NULL, :notes, NULL, NOW())
    ");
    $tx->execute([
      ':cid'     => $cid,
      ':paid_at' => $paidAtSQL,
      ':segment' => $segment, // will be non-NULL
      ':amt'     => $amount,
      ':ref'     => $ref !== '' ? $ref : ('Salary — '.$staffName.' — '.$payMonth),
      ':notes'   => $notes !== '' ? $notes : null,
    ]);

    audit_log('payroll.salary.create','staff',(int)$staffId,[
      'amount'             => $amount,
      'pay_month'          => $payMonth,
      'period_start'       => $periodFrom,
      'period_end'         => $periodTo,
      'paid_at'            => $paidAtSQL,
      'segment'            => $segment,
      '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.';
  }
}

/** Render */
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>
    <?php if ($staff): ?>
      <div class="text-muted">Staff: <?= e($staffName) ?> · Department: <?= e($department) ?></div>
    <?php else: ?>
      <div class="text-muted">Choose a staff member to continue.</div>
    <?php endif; ?>
  </div>
  <div>
    <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; ?>

<?php if (!$staff): ?>
  <!-- Step 1: pick staff -->
  <div class="card shadow-sm">
    <form method="post" class="card-body row g-3">
      <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
      <input type="hidden" name="action" value="select_staff">
      <input type="hidden" name="return" value="<?= e($returnUrl) ?>">

      <div class="col-md-8">
        <label class="form-label">Staff Member</label>
        <select name="staff_id" class="form-select" required>
          <option value="">— Select staff —</option>
          <?php foreach ($staffList as $st): ?>
            <option value="<?= (int)$st['id'] ?>">
              <?= e($st['full_name'].' ('.$st['department'].')') ?>
            </option>
          <?php endforeach; ?>
        </select>
      </div>
      <div class="col-md-4 d-flex align-items-end">
        <button class="btn btn-dark w-100">Continue</button>
      </div>
    </form>
  </div>

<?php else: ?>
  <!-- Step 2: Salary period summary -->
  <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 } ?>

  <!-- Step 2: Salary form -->
  <form method="post" class="row g-3">
    <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
    <input type="hidden" name="action" value="save">
    <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"
             value="<?= e('Salary — '.$staffName.' — '.$payMonth) ?>">
    </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 endif; ?>

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