Report with Warnings

const startDate = new Date(`${dv.current()["Start Date"]}`);
const endDate   = new Date(`${dv.current()["End Date"]}`);
 
// ===================== CONFIG =====================
const REMOTE_MEDIUMS = ["phone", "teams", "writeupp-online"];
const IN_PERSON_KEYS = ["in-person"];     // add variants if needed: ["in-person","in person"]
const WARN_AMBER = 65;                    // % threshold for Amber
const WARN_RED   = 60;                    // % threshold for Red
const SHOW_OTHER_IF_NONZERO = true;       // show "Other Total" only if > 0
const MIN_SESSION_HOURS = 0.5;            // 30 minutes
// ==================================================
 
// Helpers
const fmt = n => isFinite(n) ? parseFloat(Number(n).toFixed(2)).toString() : "0";
const norm = s => String(s ?? "")
  .toLowerCase()
  .trim()
  .replace(/[_\s]+/g, "-"); // "In Person" => "in-person"
 
// ──────────────────────────────────────────────────────────
// Fetch pages with the #clienthours tag in the right folder
let pages = dv
  .pages('"100 CPD Record" and #clienthours')
  .where(p => {
    const fileDate = new Date(p.date);
    const hrs = Number(p.hours) || 0;
    return fileDate >= startDate && fileDate <= endDate && hrs >= MIN_SESSION_HOURS;
  })
  .sort(p => p.date, "asc");
 
// Debug info
dv.paragraph(`Total records fetched: ${pages.length}`);
 
if (pages.length === 0) {
  dv.paragraph("No records found for the specified query.");
} else {
  // ────────────── Aggregate by “medium” ──────────────
  const groupedData   = {}; // key: original medium label
  let   grandTotalHrs = 0;
 
  pages.forEach(p => {
    const mediumLabel = p.medium || "No medium";
    if (!groupedData[mediumLabel]) {
      groupedData[mediumLabel] = { medium: mediumLabel, totalHours: 0 };
    }
    const hrs = Number(p.hours) || 0;
    groupedData[mediumLabel].totalHours += hrs;
    grandTotalHrs += hrs;
  });
 
  if (grandTotalHrs === 0) {
    dv.paragraph("No hours recorded in the selected period.");
  } else {
    // ─────────────── Classify into In-Person / Remote / Other ───────────────
    const inPersonSet = new Set(IN_PERSON_KEYS.map(norm));
    const remoteSet   = new Set(REMOTE_MEDIUMS.map(norm));
 
    let inPersonHours = 0;
    let remoteHours   = 0;
    let otherHours    = 0;
 
    for (const g of Object.values(groupedData)) {
      const key = norm(g.medium);
      if (inPersonSet.has(key)) {
        inPersonHours += g.totalHours;
      } else if (remoteSet.has(key)) {
        remoteHours += g.totalHours;
      } else {
        otherHours += g.totalHours;
      }
    }
 
    const inPersonPct = (inPersonHours / grandTotalHrs) * 100;
    const remotePct   = (remoteHours   / grandTotalHrs) * 100;
    const otherPct    = (otherHours    / grandTotalHrs) * 100;
 
    // ─────────────── Build compact totals table ───────────────
    const rows = [
      ["**In-Person Total**", `**${fmt(inPersonHours)}**`, `**${fmt(inPersonPct)}%**`],
      ["**Remote Total (phone/Teams/writeupp-online)**", `**${fmt(remoteHours)}**`, `**${fmt(remotePct)}%**`],
    ];
 
    if (SHOW_OTHER_IF_NONZERO && otherHours > 0.0001) {
      rows.push(["**Other Total**", `**${fmt(otherHours)}**`, `**${fmt(otherPct)}%**`]);
    }
 
    rows.push(["**Grand Total**", `**${fmt(grandTotalHrs)}**`, "**100%**"]);
 
    dv.table(["Category", "Total Hours", "Percentage of Total"], rows);
 
    // ─────────────── In-person warning banner ───────────────
    let status = `✅ In-person percentage is healthy (${fmt(inPersonPct)}%).`;
    if (inPersonPct < WARN_AMBER && inPersonPct >= WARN_RED) {
      status = `🟠 Amber: In-person percentage is approaching a critically low level (${fmt(inPersonPct)}% < ${WARN_AMBER}%).`;
    } else if (inPersonPct < WARN_RED) {
      status = `🔴 Red: In-person percentage is critically low (${fmt(inPersonPct)}% < ${WARN_RED}%).`;
    }
 
    dv.paragraph(
      `**In-Person Check:** ${status}\n` +
      `• In-person hours: ${fmt(inPersonHours)} of ${fmt(grandTotalHrs)} total\n` +
      `• Thresholds — Amber: < ${WARN_AMBER}% | Red: < ${WARN_RED}%`
    );
  }
}