<?php
// Monthly Report (Section 19, B5/C3, Phase 10) — read-only over the same
// tables as everywhere else, so it can never disagree with the entries.
// Charts (Chart.js, CDN) load only on this page — Section 13's performance
// budget keeps them off every other screen.
require_once __DIR__ . '/includes/auth.php';
require_once __DIR__ . '/includes/visitor_log.php';
log_visit();
require_login();

$db = get_db();

$month = resolve_viewed_month($_GET['month'] ?? null);
$prevMonth = adjacent_month($month, -1);
$nextMonth = adjacent_month($month, 1);
[$start, $end] = month_date_range($month);

$savings = get_month_savings($month);

// ---- Category table: Planned / Actual / Difference ----
// Categories with neither a plan nor any spending this month are omitted
// (Section 19, point 2) — nothing to report on them.
$budgetMap = get_month_budget_map($month);
$categoryTotalsRaw = get_month_category_totals($month);

$actualById = [];
foreach ($categoryTotalsRaw as $row) {
    $actualById[(int) $row['id']] = $row;
}

$allCategoryIds = array_unique(array_merge(array_map('intval', array_keys($budgetMap)), array_keys($actualById)));

$categoryRows = [];
if ($allCategoryIds) {
    $missingIds = array_diff($allCategoryIds, array_keys($actualById));
    $extraInfo = [];
    if ($missingIds) {
        $placeholders = implode(',', array_fill(0, count($missingIds), '?'));
        $stmt = $db->prepare("SELECT id, name, color FROM categories WHERE id IN ($placeholders)");
        $stmt->execute(array_values($missingIds));
        foreach ($stmt->fetchAll() as $row) {
            $extraInfo[(int) $row['id']] = $row;
        }
    }

    foreach ($allCategoryIds as $cid) {
        $info = $actualById[$cid] ?? $extraInfo[$cid] ?? null;
        if (!$info) {
            continue;
        }
        $planned = isset($budgetMap[$cid]) ? (float) $budgetMap[$cid] : 0.0;
        $actual = isset($actualById[$cid]) ? (float) $actualById[$cid]['total'] : 0.0;
        $categoryRows[] = [
            'name'    => $info['name'],
            'color'   => $info['color'],
            'planned' => $planned,
            'actual'  => $actual,
            'diff'    => $planned - $actual,
        ];
    }
    usort($categoryRows, fn ($a, $b) => $b['actual'] <=> $a['actual']);
}

$categoryTotalPlanned = array_sum(array_column($categoryRows, 'planned'));
$categoryTotalActual = array_sum(array_column($categoryRows, 'actual'));
$categoryTotalDiff = $categoryTotalPlanned - $categoryTotalActual;

// ---- Doughnut chart data ----
$doughnutLabels = array_column($categoryTotalsRaw, 'name');
$doughnutColors = array_column($categoryTotalsRaw, 'color');
$doughnutValues = array_map('floatval', array_column($categoryTotalsRaw, 'total'));

// ---- Six-month trend (ending at the viewed month) ----
$trend = [];
for ($i = 5; $i >= 0; $i--) {
    $m = adjacent_month($month, -$i);
    $trend[] = [
        'label'   => month_name($m),
        'actual'  => (float) get_month_expense_total($m),
        'planned' => (float) get_month_planned_total($m),
    ];
}
$trendLabels = array_column($trend, 'label');
$trendActual = array_column($trend, 'actual');
$trendPlanned = array_column($trend, 'planned');
$hasAnyPlanned = array_sum($trendPlanned) > 0;

// ---- By person ----
$byPersonStmt = $db->prepare(
    'SELECT u.display_name, COUNT(*) AS cnt, SUM(e.amount) AS total
     FROM expenses e JOIN users u ON u.id = e.user_id
     WHERE e.expense_date BETWEEN :start AND :end
     GROUP BY u.id, u.display_name
     ORDER BY total DESC'
);
$byPersonStmt->execute(['start' => $start, 'end' => $end]);
$byPerson = $byPersonStmt->fetchAll();

// ---- By payment method ----
$byMethodStmt = $db->prepare(
    "SELECT COALESCE(pm.name, 'Not specified') AS method_name, SUM(e.amount) AS total
     FROM expenses e LEFT JOIN payment_methods pm ON pm.id = e.payment_method_id
     WHERE e.expense_date BETWEEN :start AND :end
     GROUP BY pm.id, method_name
     ORDER BY total DESC"
);
$byMethodStmt->execute(['start' => $start, 'end' => $end]);
$byMethod = $byMethodStmt->fetchAll();

// ---- Top 5 largest expenses ----
// Reuses the same row shape as get_recent_expenses() so
// format_recent_expense_row()/render_expense_row() and the shared edit
// modal work here unchanged — just ordered by amount instead of recency.
$top5Stmt = $db->prepare(
    'SELECT e.id, e.expense_date, e.amount, e.description, e.category_id, e.payment_method_id, e.user_id,
            c.name AS category_name, c.color AS category_color,
            u.display_name AS user_display_name
     FROM expenses e
     JOIN categories c ON c.id = e.category_id
     JOIN users u ON u.id = e.user_id
     WHERE e.expense_date BETWEEN :start AND :end
     ORDER BY e.amount DESC, e.id ASC
     LIMIT 5'
);
$top5Stmt->execute(['start' => $start, 'end' => $end]);
$top5 = array_map('format_recent_expense_row', $top5Stmt->fetchAll());

// The shared edit modal (below) needs these in scope.
$categories = get_active_expense_categories();
$paymentMethods = get_active_payment_methods();
$visibleCategories = array_slice($categories, 0, 7);
$hiddenCategories = array_slice($categories, 7);

$pageTitle = 'Report — ' . month_label($month);
$currentPage = 'reports';
require __DIR__ . '/includes/layout/header.php';
?>

<div class="d-flex align-items-center justify-content-between mb-3">
  <div class="sec-title fs-5"><?= e(month_label($month)) ?> report</div>
  <div class="d-flex gap-2">
    <a class="mini-nav" href="?month=<?= e($prevMonth) ?>" aria-label="Previous month, <?= e(month_label($prevMonth)) ?>"><i class="bi bi-chevron-left"></i></a>
    <a class="mini-nav" href="?month=<?= e($nextMonth) ?>" aria-label="Next month, <?= e(month_label($nextMonth)) ?>"><i class="bi bi-chevron-right"></i></a>
  </div>
</div>

<!-- ============ 1) Savings strip ============ -->
<section class="card-x p-3 p-lg-4 mb-3 mb-lg-4" aria-label="Savings summary">
  <div class="row text-center g-2">
    <div class="col-4">
      <div class="sec-sub">Income</div>
      <div class="fw-bold tnum fs-5"><?= e($savings['income_formatted']) ?></div>
    </div>
    <div class="col-4">
      <div class="sec-sub">Expenses</div>
      <div class="fw-bold tnum fs-5"><?= e($savings['expense_formatted']) ?></div>
    </div>
    <div class="col-4">
      <div class="sec-sub"><?= $savings['is_negative'] ? 'Overspent' : 'Saved' ?></div>
      <div class="fw-bold tnum fs-5" style="color:<?= $savings['is_negative'] ? '#dc3545' : 'var(--good)' ?>"><?= e($savings['saved_formatted']) ?></div>
    </div>
  </div>
</section>

<!-- ============ 2) Planned / Actual / Difference ============ -->
<section class="card-x p-3 p-lg-4 mb-3 mb-lg-4" aria-label="Planned versus actual">
  <div class="sec-title mb-2">Planned vs. actual</div>
  <?php if (!$categoryRows): ?>
    <p class="text-secondary small mb-0">No budgets or expenses yet in <?= e(month_name($month)) ?>.</p>
  <?php else: ?>

    <!-- Phone/tablet (< 992px): stacked rows, same pattern as the
         dashboard's "Spending by category" — one line per category, no
         columns to squeeze onto a narrow screen, no sideways scrolling
         needed to compare Planned vs. Actual. -->
    <div class="d-lg-none">
      <?php foreach ($categoryRows as $row): ?>
        <div class="pv-row" style="--c:<?= e($row['color']) ?>">
          <div class="pv-top">
            <span class="hdot"></span>
            <span class="pv-name"><?= e($row['name']) ?></span>
            <span class="pv-diff tnum" style="color:<?= $row['diff'] < 0 ? '#dc3545' : 'var(--good)' ?>">
              <?= $row['planned'] > 0 ? e(($row['diff'] < 0 ? '−' : '+') . format_money(abs($row['diff']))) : '—' ?>
            </span>
          </div>
          <div class="pv-sub tnum">
            Planned <?= $row['planned'] > 0 ? e(format_money($row['planned'])) : '—' ?>
            · Actual <?= e(format_money($row['actual'])) ?>
          </div>
          <?php if ($row['planned'] > 0): ?>
            <div class="htrack mt-2">
              <span style="width:<?= e((string) min(100, (int) round($row['actual'] / $row['planned'] * 100))) ?>%;background:<?= $row['diff'] < 0 ? '#dc3545' : e($row['color']) ?>"></span>
            </div>
          <?php endif; ?>
        </div>
      <?php endforeach; ?>
      <div class="pv-row pv-total">
        <div class="pv-top">
          <span class="pv-name">Total</span>
          <span class="pv-diff tnum" style="color:<?= $categoryTotalDiff < 0 ? '#dc3545' : 'var(--good)' ?>">
            <?= $categoryTotalPlanned > 0 ? e(($categoryTotalDiff < 0 ? '−' : '+') . format_money(abs($categoryTotalDiff))) : '—' ?>
          </span>
        </div>
        <div class="pv-sub tnum">
          Planned <?= $categoryTotalPlanned > 0 ? e(format_money($categoryTotalPlanned)) : '—' ?>
          · Actual <?= e(format_money($categoryTotalActual)) ?>
        </div>
      </div>
    </div>

    <!-- Desktop (≥ 992px): the full table, with room to breathe. -->
    <div class="table-responsive d-none d-lg-block">
      <table class="table table-sm align-middle mb-0">
        <thead>
          <tr class="text-secondary small">
            <th>Category</th>
            <th class="text-end">Planned</th>
            <th class="text-end">Actual</th>
            <th class="text-end">Difference</th>
          </tr>
        </thead>
        <tbody>
          <?php foreach ($categoryRows as $row): ?>
            <tr>
              <td><span class="hdot me-2" style="background:<?= e($row['color']) ?>"></span><?= e($row['name']) ?></td>
              <td class="text-end tnum"><?= $row['planned'] > 0 ? e(format_money($row['planned'])) : '—' ?></td>
              <td class="text-end tnum"><?= e(format_money($row['actual'])) ?></td>
              <td class="text-end tnum" style="color:<?= $row['diff'] < 0 ? '#dc3545' : 'var(--good)' ?>">
                <?= $row['planned'] > 0 ? e(($row['diff'] < 0 ? '−' : '+') . format_money(abs($row['diff']))) : '—' ?>
              </td>
            </tr>
            <?php if ($row['planned'] > 0): ?>
              <tr>
                <td colspan="4" class="pt-0 pb-2">
                  <div class="htrack"><span style="width:<?= e((string) min(100, (int) round($row['actual'] / $row['planned'] * 100))) ?>%;background:<?= $row['diff'] < 0 ? '#dc3545' : e($row['color']) ?>"></span></div>
                </td>
              </tr>
            <?php endif; ?>
          <?php endforeach; ?>
        </tbody>
        <tfoot>
          <tr class="fw-bold border-top">
            <td>Total</td>
            <td class="text-end tnum"><?= $categoryTotalPlanned > 0 ? e(format_money($categoryTotalPlanned)) : '—' ?></td>
            <td class="text-end tnum"><?= e(format_money($categoryTotalActual)) ?></td>
            <td class="text-end tnum" style="color:<?= $categoryTotalDiff < 0 ? '#dc3545' : 'var(--good)' ?>">
              <?= $categoryTotalPlanned > 0 ? e(($categoryTotalDiff < 0 ? '−' : '+') . format_money(abs($categoryTotalDiff))) : '—' ?>
            </td>
          </tr>
        </tfoot>
      </table>
    </div>
  <?php endif; ?>
</section>

<div class="row g-3 g-lg-4">
  <!-- ============ 3) Doughnut: category breakdown ============ -->
  <div class="col-12 col-lg-6">
    <section class="card-x p-3 p-lg-4 mb-3 mb-lg-4" aria-label="Spending by category">
      <div class="sec-title mb-2">Spending by category</div>
      <?php if (!$doughnutValues): ?>
        <p class="text-secondary small mb-0">No expenses yet in <?= e(month_name($month)) ?>.</p>
      <?php else: ?>
        <div style="max-width:320px;margin:0 auto;"><canvas id="categoryDoughnut" role="img" aria-label="Doughnut chart of spending by category"></canvas></div>
      <?php endif; ?>
    </section>
  </div>

  <!-- ============ 4) Six-month trend ============ -->
  <div class="col-12 col-lg-6">
    <section class="card-x p-3 p-lg-4 mb-3 mb-lg-4" aria-label="Six month spending trend">
      <div class="sec-title mb-2">6-month trend</div>
      <canvas id="trendChart" role="img" aria-label="Bar chart of spending over the last six months"></canvas>
    </section>
  </div>
</div>

<div class="row g-3 g-lg-4">
  <!-- ============ 5) By person ============ -->
  <div class="col-12 col-lg-6">
    <section class="card-x p-3 p-lg-4 mb-3 mb-lg-4" aria-label="Spending by person">
      <div class="sec-title mb-2">By person</div>
      <?php if (!$byPerson): ?>
        <p class="text-secondary small mb-0">No expenses yet in <?= e(month_name($month)) ?>.</p>
      <?php else: ?>
        <table class="table table-sm mb-0">
          <thead><tr class="text-secondary small"><th>Person</th><th class="text-end">Entries</th><th class="text-end">Total</th></tr></thead>
          <tbody>
            <?php foreach ($byPerson as $row): ?>
              <tr>
                <td><?= e($row['display_name']) ?></td>
                <td class="text-end tnum"><?= e((string) $row['cnt']) ?></td>
                <td class="text-end tnum"><?= e(format_money($row['total'])) ?></td>
              </tr>
            <?php endforeach; ?>
          </tbody>
        </table>
      <?php endif; ?>
    </section>
  </div>

  <!-- ============ 6) By payment method ============ -->
  <div class="col-12 col-lg-6">
    <section class="card-x p-3 p-lg-4 mb-3 mb-lg-4" aria-label="Spending by payment method">
      <div class="sec-title mb-2">By payment method</div>
      <?php if (!$byMethod): ?>
        <p class="text-secondary small mb-0">No expenses yet in <?= e(month_name($month)) ?>.</p>
      <?php else: ?>
        <table class="table table-sm mb-0">
          <thead><tr class="text-secondary small"><th>Method</th><th class="text-end">Total</th></tr></thead>
          <tbody>
            <?php foreach ($byMethod as $row): ?>
              <tr>
                <td><?= e($row['method_name']) ?></td>
                <td class="text-end tnum"><?= e(format_money($row['total'])) ?></td>
              </tr>
            <?php endforeach; ?>
          </tbody>
        </table>
      <?php endif; ?>
    </section>
  </div>
</div>

<!-- ============ 7) Top 5 largest expenses ============ -->
<section class="card-x p-3 p-lg-4" aria-label="Top 5 largest expenses">
  <div class="sec-title mb-2">Top 5 largest expenses</div>
  <?php if (!$top5): ?>
    <p class="text-secondary small mb-0">No expenses yet in <?= e(month_name($month)) ?>.</p>
  <?php else: ?>
    <div>
      <?php foreach ($top5 as $item): ?>
        <?php render_expense_row($item); ?>
      <?php endforeach; ?>
    </div>
  <?php endif; ?>
</section>

<?php require __DIR__ . '/includes/layout/edit_modal.php'; ?>

<!-- Toasts -->
<div class="toast-container position-fixed bottom-0 start-50 translate-middle-x p-3" id="toasts"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>
<script>
(function () {
  // Each chart is instantiated independently and wrapped in try/catch: if
  // the Chart.js CDN request ever fails (or a future version pin turns out
  // not to exist there), the person sees one plain-language message next to
  // the empty box instead of a silent, unexplained blank card — and a
  // failure in one chart can't also blank out the other one alongside it.
  function showChartFallback(canvas, message) {
    if (!canvas) {
      return;
    }
    const note = document.createElement('p');
    note.className = 'text-secondary small mb-0';
    note.textContent = message;
    canvas.replaceWith(note);
  }

  const doughnutCtx = document.getElementById('categoryDoughnut');
  if (doughnutCtx) {
    try {
      if (typeof Chart === 'undefined') {
        throw new Error('Chart.js did not load');
      }
      new Chart(doughnutCtx, {
        type: 'doughnut',
        data: {
          labels: <?= json_encode($doughnutLabels, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
          datasets: [{
            data: <?= json_encode($doughnutValues) ?>,
            backgroundColor: <?= json_encode($doughnutColors, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
            borderWidth: 0
          }]
        },
        options: {
          plugins: { legend: { position: 'bottom', labels: { boxWidth: 10, font: { size: 11 } } } },
          cutout: '65%'
        }
      });
    } catch (err) {
      showChartFallback(doughnutCtx, "Couldn't load the chart — the numbers are still in the table above.");
    }
  }

  const trendCtx = document.getElementById('trendChart');
  if (trendCtx) {
    try {
      if (typeof Chart === 'undefined') {
        throw new Error('Chart.js did not load');
      }
      const datasets = [{
        label: 'Spent',
        data: <?= json_encode($trendActual) ?>,
        backgroundColor: '#5a5bd8',
        borderRadius: 6
      }];
      <?php if ($hasAnyPlanned): ?>
      datasets.push({
        label: 'Planned',
        type: 'line',
        data: <?= json_encode($trendPlanned) ?>,
        borderColor: '#d9a62e',
        backgroundColor: '#d9a62e',
        tension: 0.3,
        pointRadius: 3
      });
      <?php endif; ?>
      new Chart(trendCtx, {
        type: 'bar',
        data: {
          labels: <?= json_encode($trendLabels, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
          datasets: datasets
        },
        options: {
          plugins: { legend: { display: <?= $hasAnyPlanned ? 'true' : 'false' ?> } },
          scales: { y: { beginAtZero: true } }
        }
      });
    } catch (err) {
      showChartFallback(trendCtx, "Couldn't load the chart — try refreshing the page.");
    }
  }
})();
</script>

<?php require __DIR__ . '/includes/layout/footer.php'; ?>
