import { notFound } from "next/navigation";
import { EmployeeDetail } from "@/components/employees/EmployeeDetail";
import { currentUserId } from "@/lib/auth/session";
import { withUser } from "@/lib/db";
import { todayIso } from "@/lib/format";
import { breadcrumbLabel, loadOrgMaps } from "@/lib/org";
import { loadPlacements, loadReportingLines } from "@/lib/placement";
import { loadOpenPositions } from "@/lib/positions";

type PageProps = { params: Promise<{ id: string }> };

export default async function EmployeeDetailPage({ params }: PageProps) {
  const { id } = await params;
  const today = todayIso();

  const data = await withUser(await currentUserId(), async (tx) => {
    // Vorgesetzte und direkte Berichte stehen nirgends als Spalte — sie
    // kommen aus om_reporting_lines(). Beide Abfragen schränken *in* der
    // Funktion ein, es wandern also neun Zeilen über die Leitung und nicht
    // achthundert.
    const [employee, ownLines, reports, history, dependents, notes, orgMaps, placements, openPositions] =
      await Promise.all([
        tx.selectFrom("employees").selectAll().where("id", "=", id).executeTakeFirst(),
        loadReportingLines(tx, today, { employeeId: id }),
        loadReportingLines(tx, today, { actingManagerId: id }),
        tx
          .selectFrom("employee_history")
          .selectAll()
          .where("employee_id", "=", id)
          .orderBy("event_date", "desc")
          .orderBy("created_at", "desc")
          .execute(),
        tx.selectFrom("employee_dependents").selectAll().where("employee_id", "=", id).orderBy("created_at").execute(),
        tx.selectFrom("employee_notes").selectAll().where("employee_id", "=", id).orderBy("created_at", "desc").execute(),
        loadOrgMaps(tx),
        loadPlacements(tx, { asOf: today, employeeIds: [id] }),
        loadOpenPositions(tx),
      ]);

    if (!employee) return null;
    const line = ownLines[0] ?? null;

    // Namen für die beteiligten Personen in einem Zug: die Vertretung, die
    // formal zuständige Leitung und die direkten Berichte.
    const relatedIds = Array.from(
      new Set(
        [line?.acting_manager_id, line?.formal_manager_id, ...reports.map((r) => r.employee_id)].filter(
          (x): x is string => Boolean(x)
        )
      )
    );
    const relatedRows = relatedIds.length
      ? await tx
          .selectFrom("employees")
          .select(["id", "first_name", "last_name", "job_title", "status"])
          .where("id", "in", relatedIds)
          .execute()
      : [];

    return {
      employee,
      line,
      reports,
      history,
      dependents,
      notes,
      orgMaps,
      placement: placements.get(id) ?? null,
      openPositions,
      byId: new Map(relatedRows.map((e) => [e.id, e])),
    };
  });

  if (!data) notFound();
  const { employee, line, reports, history, dependents, notes, orgMaps, placement, openPositions, byId } = data;

  return (
    <EmployeeDetail
      employee={employee}
      placement={
        placement && {
          positionNumber: placement.positionNumber,
          jobTitle: placement.jobTitle,
          isChief: placement.isChief,
          current: placement.current,
        }
      }
      breadcrumb={breadcrumbLabel(orgMaps, placement?.orgUnitId)}
      manager={(line?.acting_manager_id ? byId.get(line.acting_manager_id) : null) ?? null}
      // Nur wenn eine Vertretung im Spiel ist — sonst stünde dieselbe Person
      // zweimal da.
      formalManager={
        line?.formal_manager_id && line.formal_manager_id !== line.acting_manager_id
          ? (byId.get(line.formal_manager_id) ?? null)
          : null
      }
      directReports={reports.flatMap((r) => {
        const e = byId.get(r.employee_id);
        return e ? [e] : [];
      })}
      history={history ?? []}
      dependents={dependents ?? []}
      notes={notes ?? []}
      locations={orgMaps.locationList}
      openPositions={openPositions}
    />
  );
}
