import { Suspense } from "react";
import { ReportsPageClient } from "@/components/reports/ReportsPageClient";
import {
  aggregateEvents,
  aggregateReport,
  parseEventDateParam,
  parseEventGroupDimension,
  parseEventSplitDimension,
  parseEventType,
  parseGroupDimension,
  parseIsoDateParam,
  parseMeasure,
  parseMode,
  parseSplitDimension,
  sumValues,
  totalForRows,
} from "@/lib/reports";
import { loadEventHistory, loadOrgLookups, loadSnapshotEmployees } from "@/lib/reports-data";
import { currentUserId } from "@/lib/auth/session";
import { withUser } from "@/lib/db";

type SearchParams = {
  mode?: string;
  measure?: string;
  group?: string;
  split?: string;
  division?: string;
  location?: string;
  status?: string;
  employment?: string;
  asOf?: string;
  eventType?: string;
  from?: string;
  to?: string;
};

export default async function ReportsPage({ searchParams }: { searchParams: Promise<SearchParams> }) {
  const params = await searchParams;
  const mode = parseMode(params.mode);

  // Both modes are parsed up front so the data load can start before
  // anything is awaited. They group by different dimension sets, so the
  // parsed values stay separate rather than being widened into one type.
  const asOf = parseIsoDateParam(params.asOf);
  const eventGroup = parseEventGroupDimension(params.group);
  const eventSplit = parseEventSplitDimension(params.split);
  const eventType = parseEventType(params.eventType);
  const from = parseEventDateParam(params.from);
  const to = parseEventDateParam(params.to);
  const measure = parseMeasure(params.measure);
  const group = parseGroupDimension(params.group);
  const split = parseSplitDimension(params.split);

  // The report data depends on neither the org lookups nor on who is signed
  // in, so all three go out together. Against a hosted database a round trip
  // costs about as much as the query itself, which made this page's three
  // sequential waves its dominant cost.
  const userId = await currentUserId();

  // Alles in einer Transaktion — dort gilt der Sitzungskontext, und der
  // Lesestand ist über alle Abfragen hinweg derselbe. Vorher waren es drei
  // Wellen nacheinander, was gegen eine entfernte Datenbank der teuerste
  // Teil dieser Seite war.
  const { lookups, divisions, locations, events, employees, savedReports } = await withUser(userId, async (tx) => {
    const [{ lookups, divisions, locations }, events, employees, savedReports] = await Promise.all([
      loadOrgLookups(tx),
      mode === "events"
        ? loadEventHistory(tx, {
            eventType: eventType ?? undefined,
            division: params.division,
            location: params.location,
            from,
            to,
          })
        : Promise.resolve([]),
      mode === "snapshot"
        ? loadSnapshotEmployees(tx, {
            division: params.division,
            location: params.location,
            status: params.status,
            employment: params.employment,
            asOf,
          })
        : Promise.resolve([]),
      userId
        ? tx
            .selectFrom("saved_reports")
            .select(["id", "name", "config"])
            .where("created_by", "=", userId)
            .orderBy("created_at", "desc")
            .execute()
        : Promise.resolve([]),
    ]);
    return { lookups, divisions, locations, events, employees, savedReports };
  });

  if (mode === "events") {
    const rows = aggregateEvents(events, eventGroup, eventSplit, lookups);

    return (
      <Suspense>
        <ReportsPageClient
          mode="events"
          eventGroup={eventGroup}
          eventSplit={eventSplit ?? ""}
          eventType={eventType ?? ""}
          eventFilters={{ division: params.division ?? "", location: params.location ?? "", from: from ?? "", to: to ?? "" }}
          rows={rows}
          total={sumValues(rows)}
          recordCount={events.length}
          divisions={divisions}
          locations={locations}
          savedReports={savedReports}
        />
      </Suspense>
    );
  }

  const rows = aggregateReport(employees, measure, group, split, lookups, asOf);

  return (
    <Suspense>
      <ReportsPageClient
        mode="snapshot"
        measure={measure}
        group={group}
        split={split ?? ""}
        asOf={asOf ?? ""}
        filters={{
          division: params.division ?? "",
          location: params.location ?? "",
          status: params.status ?? "",
          employment: params.employment ?? "",
        }}
        rows={rows}
        total={totalForRows(rows, measure)}
        recordCount={employees.length}
        divisions={divisions}
        locations={locations}
        savedReports={savedReports}
      />
    </Suspense>
  );
}
