const startDate = new Date(dv.current()["Start Date"]);
const endDate = new Date(dv.current()["End Date"]);
 
// Fetch pages with the 'clienthours' tag
let pages = dv
  .pages('"100 CPD Record" and #clienthours')
  .where(p => {
    const fileDate = new Date(p.date);
    const hours = Number(p.hours ?? 0);
    return fileDate >= startDate && fileDate <= endDate && hours > 0.5;
  })
  .sort(p => p.date, "asc");
 
dv.paragraph(`Total records fetched: ${pages.length}`);
if (pages.length === 0) {
  dv.paragraph("No records found for the specified query.");
} else {
  const groupedData = {};
 
  pages.forEach(p => {
    const agency = p.agency || "No Agency";
    const clientref = p.clientref || "Not stated";
    const key = `${agency} - ${clientref}`;
    const hours = Number(p.hours ?? 0);
 
    // Handle medium safely
    const rawMedium = p.medium;
    const medium = Array.isArray(rawMedium)
      ? String(rawMedium[0]).toLowerCase()
      : String(rawMedium || "unspecified").toLowerCase();
 
    if (!groupedData[key]) {
      groupedData[key] = {
        agency,
        clientref,
        totalHours: 0,
        mediumHours: {}  // key = medium, value = total hours
      };
    }
 
    groupedData[key].totalHours += hours;
    groupedData[key].mediumHours[medium] = (groupedData[key].mediumHours[medium] || 0) + hours;
  });
 
  // Filter out zero-hour clients
  const filteredGroups = Object.values(groupedData).filter(
    group => group.totalHours > 0
  );
 
  // Calculate most used medium based on HOURS
  filteredGroups.forEach(group => {
    const { mediumHours, totalHours } = group;
    group.mostUsedMedium = "unclear";
 
    for (const [medium, hrs] of Object.entries(mediumHours)) {
      if (hrs > totalHours / 2) {
        group.mostUsedMedium = medium;
        break;
      }
    }
  });
 
  // Recalculate totals
  const clientsByAgency = {};
  let uniqueClients = new Set();
  let lineCount = 0;
  let grandTotalFiltered = 0;
  const agencyFilteredSubtotal = {};
 
  filteredGroups.forEach(group => {
    const { agency, clientref, totalHours } = group;
 
    uniqueClients.add(clientref);
 
    if (!clientsByAgency[agency]) {
      clientsByAgency[agency] = new Set();
    }
    clientsByAgency[agency].add(clientref);
 
    grandTotalFiltered += totalHours;
    agencyFilteredSubtotal[agency] = (agencyFilteredSubtotal[agency] || 0) + totalHours;
  });
 
  const singleSessionClients = filteredGroups.filter(
    group => group.totalHours <= 1
  ).length;
 
  const tableData = [];
 
  // Sort and build rows. Use Markdown bold, not HTML, so Pandoc/Zettlr preserves cells.
  filteredGroups
    .sort((a, b) => {
      const diff = b.totalHours - a.totalHours;
      if (diff !== 0) return diff;
      const agencyCmp = a.agency.localeCompare(b.agency);
      if (agencyCmp !== 0) return agencyCmp;
      return a.clientref.localeCompare(b.clientref);
    })
    .forEach(group => {
      tableData.push([
        `**${group.agency} - ${group.clientref} Total**`,
        `**${group.totalHours.toFixed(2)}**`,
        group.mostUsedMedium
      ]);
      lineCount++;
    });
 
  // Divider
  tableData.push(["---", "", ""]);
 
  // Agency subtotals
  Object.entries(agencyFilteredSubtotal)
    .sort((a, b) => a[0].localeCompare(b[0]))
    .forEach(([agency, subtotal]) => {
      tableData.push([
        `**${agency} Subtotal**`,
        `**${subtotal.toFixed(2)}**`,
        ""
      ]);
      lineCount++;
    });
 
  // Grand total
  tableData.push(["---", "", ""]);
  tableData.push([
    "**Grand Total**",
    `**${grandTotalFiltered.toFixed(2)}**`,
    ""
  ]);
 
  // Live Obsidian view. Dataview's dv.table does not expose Markdown alignment,
  // but the export block below emits a right-aligned Markdown separator for Pandoc.
  dv.table(
    ["Group", "Total Hours", "Most Used Medium"],
    tableData
  );
 
  // Client counts
  dv.paragraph("**Clients per agency:**");
  Object.entries(clientsByAgency)
    .sort((a, b) => a[0].localeCompare(b[0]))
    .forEach(([agency, set]) => {
      dv.paragraph(`- **${agency}**: ${set.size}`);
    });
 
  dv.paragraph(`Total unique clients (with >0 hours): **${uniqueClients.size}**`);
  dv.paragraph(`Clients with total hours ≤ 1 (single sessions): **${singleSessionClients}**`);
//  dv.paragraph(`Total lines in table (excluding grand total): **${lineCount}**`);
}
const startDate = new Date("2022-11-01");
const endDate = new Date("2031-04-30");
 
const escapeCell = (value) => String(value ?? "")
  .replace(/\|/g, "\\|")
  .replace(/\n/g, " ")
  .trim();
 
// Fetch pages with the 'clienthours' tag
let pages = dv
  .pages('"100 CPD Record" and #clienthours')
  .where(p => {
    const fileDate = new Date(p.date);
    const hours = Number(p.hours ?? 0);
    return fileDate >= startDate && fileDate <= endDate && hours > 0.5;
  })
  .sort(p => p.date, "asc");
 
const lines = [`Total records fetched: ${pages.length}`, ""];
 
if (pages.length === 0) {
  lines.push("No records found for the specified query.");
} else {
  const groupedData = {};
 
  pages.forEach(p => {
    const agency = p.agency || "No Agency";
    const clientref = p.clientref || "Not stated";
    const key = `${agency} - ${clientref}`;
    const hours = Number(p.hours ?? 0);
 
    const rawMedium = p.medium;
    const medium = Array.isArray(rawMedium)
      ? String(rawMedium[0]).toLowerCase()
      : String(rawMedium || "unspecified").toLowerCase();
 
    if (!groupedData[key]) {
      groupedData[key] = {
        agency,
        clientref,
        totalHours: 0,
        mediumHours: {}
      };
    }
 
    groupedData[key].totalHours += hours;
    groupedData[key].mediumHours[medium] = (groupedData[key].mediumHours[medium] || 0) + hours;
  });
 
  const filteredGroups = Object.values(groupedData).filter(
    group => group.totalHours > 0
  );
 
  filteredGroups.forEach(group => {
    const { mediumHours, totalHours } = group;
    group.mostUsedMedium = "unclear";
 
    for (const [medium, hrs] of Object.entries(mediumHours)) {
      if (hrs > totalHours / 2) {
        group.mostUsedMedium = medium;
        break;
      }
    }
  });
 
  const clientsByAgency = {};
  let uniqueClients = new Set();
  let grandTotalFiltered = 0;
  const agencyFilteredSubtotal = {};
 
  filteredGroups.forEach(group => {
    const { agency, clientref, totalHours } = group;
 
    uniqueClients.add(clientref);
 
    if (!clientsByAgency[agency]) {
      clientsByAgency[agency] = new Set();
    }
    clientsByAgency[agency].add(clientref);
 
    grandTotalFiltered += totalHours;
    agencyFilteredSubtotal[agency] = (agencyFilteredSubtotal[agency] || 0) + totalHours;
  });
 
  const singleSessionClients = filteredGroups.filter(
    group => group.totalHours <= 1
  ).length;
 
  lines.push("| Group | Total Hours | Most Used Medium |");
  lines.push("| --- | ---: | --- |");
 
  filteredGroups
    .sort((a, b) => {
      const diff = b.totalHours - a.totalHours;
      if (diff !== 0) return diff;
      const agencyCmp = a.agency.localeCompare(b.agency);
      if (agencyCmp !== 0) return agencyCmp;
      return a.clientref.localeCompare(b.clientref);
    })
    .forEach(group => {
      lines.push(`| **${escapeCell(group.agency)} - ${escapeCell(group.clientref)} Total** | **${group.totalHours.toFixed(2)}** | ${escapeCell(group.mostUsedMedium)} |`);
    });
 
  lines.push("| --- |  |  |");
 
  Object.entries(agencyFilteredSubtotal)
    .sort((a, b) => a[0].localeCompare(b[0]))
    .forEach(([agency, subtotal]) => {
      lines.push(`| **${escapeCell(agency)} Subtotal** | **${subtotal.toFixed(2)}** |  |`);
    });
 
  lines.push("| --- |  |  |");
  lines.push(`| **Grand Total** | **${grandTotalFiltered.toFixed(2)}** |  |`);
  lines.push("");
 
  lines.push("**Clients per agency:**", "");
  Object.entries(clientsByAgency)
    .sort((a, b) => a[0].localeCompare(b[0]))
    .forEach(([agency, set]) => {
      lines.push(`- **${escapeCell(agency)}**: ${set.size}`);
    });
 
  lines.push("", `Total unique clients (with >0 hours): **${uniqueClients.size}**`);
  lines.push(`Clients with total hours ≤ 1 (single sessions): **${singleSessionClients}**`);
}
 
return lines.join("\n");