"use client";

import { ChevronDown, ChevronRight } from "lucide-react";
import Link from "next/link";
import { useCallback, useMemo, useState } from "react";
import { SegmentedControl } from "@/components/ui/SegmentedControl";
import { LazyGraphOrgChart } from "./LazyGraphOrgChart";
import type { ChartNode, OrgEmployee, OrgUnitNode, OrgVacancy } from "./types";

// Die Struktursicht. Sie folgt jetzt org_units.parent_id statt einer fest
// verdrahteten Abfolge Bereich → Abteilung → Team: eine fünfte Ebene ist
// damit eine Datenfrage und keine Änderung an dieser Datei.
//
// Liste und Grafik werden aus *einem* Baum gerendert. Vorher gab es dieselbe
// Hierarchie zweimal — einmal als JSX-Schachtelung, einmal als ChartNode —
// und die beiden konnten auseinanderlaufen, ohne dass es auffiel.

type ViewMode = "list" | "graph";

type PositionTreeProps = {
  employees: OrgEmployee[];
  units: OrgUnitNode[];
  vacancies: OrgVacancy[];
};

export function PositionTree({ employees, units, vacancies }: PositionTreeProps) {
  const [expanded, setExpanded] = useState<Set<string>>(() => new Set(units.filter((u) => u.parent_id === null).map((u) => `unit-${u.id}`)));
  const [mode, setMode] = useState<ViewMode>("list");

  // useCallback-stabil: das Layout-Memo von GraphOrgChart hängt an diesen
  // Referenzen, instabile Funktionen erzwängen sonst bei jedem Re-Render ein
  // neues Dagre-Layout.
  const toggle = useCallback((id: string) => {
    setExpanded((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }, []);
  const isExpanded = useCallback((id: string) => expanded.has(id), [expanded]);

  const tree = useMemo(() => buildUnitTree(units, employees, vacancies), [units, employees, vacancies]);

  return (
    <div className="flex flex-col gap-4">
      <div className="flex justify-end">
        <SegmentedControl<ViewMode>
          value={mode}
          onChange={setMode}
          options={[
            { value: "list", label: "Liste" },
            { value: "graph", label: "Grafisch" },
          ]}
        />
      </div>
      {mode === "graph" ? (
        <LazyGraphOrgChart tree={tree} isExpanded={isExpanded} onToggle={toggle} />
      ) : (
        <div className="rounded border border-border bg-white p-4">
          {tree.map((node) => (
            <ListNode key={node.id} node={node} depth={0} expanded={expanded} onToggle={toggle} />
          ))}
        </div>
      )}
    </div>
  );
}

function ListNode({
  node,
  depth,
  expanded,
  onToggle,
}: {
  node: ChartNode;
  depth: number;
  expanded: Set<string>;
  onToggle: (id: string) => void;
}) {
  const expandable = node.children.length > 0;
  const open = expanded.has(node.id);

  return (
    <div>
      <div
        className="flex items-center gap-2 rounded px-2 py-1.5 hover:bg-surface"
        style={{ paddingLeft: depth * 24 + 8 }}
      >
        {expandable ? (
          <button
            type="button"
            onClick={() => onToggle(node.id)}
            className="shrink-0 text-ink-muted"
            aria-expanded={open}
            aria-label={open ? `${node.label} zuklappen` : `${node.label} aufklappen`}
          >
            {open ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
          </button>
        ) : (
          <span className="w-4 shrink-0" />
        )}
        {node.href ? (
          <Link
            href={node.href}
            className={node.kind === "vacancy" ? "text-sm text-brand-700 hover:underline" : "text-sm text-ink-body hover:text-brand-700 hover:underline"}
          >
            {node.label}
          </Link>
        ) : (
          <span className={node.kind === "group" ? "text-sm text-ink" : "text-sm font-semibold text-ink"}>{node.label}</span>
        )}
        {node.sublabel && (
          <span className={node.vacant ? "text-xs font-semibold text-warning-text" : "text-xs text-ink-muted"}>{node.sublabel}</span>
        )}
      </div>
      {open && node.children.map((child) => <ListNode key={child.id} node={child} depth={depth + 1} expanded={expanded} onToggle={onToggle} />)}
    </div>
  );
}

/**
 * Je Einheit: die Leitung als Kopfzeile, darunter die untergeordneten
 * Einheiten, dann die eigenen Mitarbeitenden nach Tätigkeit gruppiert und
 * zuletzt die unbesetzten Planstellen.
 */
export function buildUnitTree(units: OrgUnitNode[], employees: OrgEmployee[], vacancies: OrgVacancy[]): ChartNode[] {
  const childUnits = new Map<string | null, OrgUnitNode[]>();
  for (const u of units) {
    const list = childUnits.get(u.parent_id) ?? [];
    list.push(u);
    childUnits.set(u.parent_id, list);
  }
  for (const list of childUnits.values()) list.sort((a, b) => a.org_number.localeCompare(b.org_number));

  const chiefOf = new Map<string, OrgEmployee>();
  const staffOf = new Map<string, OrgEmployee[]>();
  for (const e of employees) {
    if (e.is_chief) chiefOf.set(e.org_unit_id, e);
    else {
      const list = staffOf.get(e.org_unit_id) ?? [];
      list.push(e);
      staffOf.set(e.org_unit_id, list);
    }
  }

  const vacantOf = new Map<string, OrgVacancy[]>();
  for (const v of vacancies) {
    const list = vacantOf.get(v.org_unit_id) ?? [];
    list.push(v);
    vacantOf.set(v.org_unit_id, list);
  }

  function build(unit: OrgUnitNode): ChartNode {
    const key = `unit-${unit.id}`;
    const chief = chiefOf.get(unit.id);

    const subUnits = (childUnits.get(unit.id) ?? []).map(build);

    // Nach Tätigkeit gruppiert: dreissig Zeilen „Maschinenbediener:in" sagen
    // weniger als eine Zeile „Maschinenbediener:in — 30x besetzt".
    const byTitle = new Map<string, OrgEmployee[]>();
    for (const e of staffOf.get(unit.id) ?? []) {
      const list = byTitle.get(e.job_title) ?? [];
      list.push(e);
      byTitle.set(e.job_title, list);
    }
    const titleGroups: ChartNode[] = Array.from(byTitle.entries())
      .sort(([a], [b]) => a.localeCompare(b, "de"))
      .map(([title, people]) => ({
        id: `${key}-job-${title}`,
        kind: "group" as const,
        label: title,
        sublabel: `${people.length}x besetzt`,
        children: people
          .slice()
          .sort((a, b) => a.last_name.localeCompare(b.last_name, "de"))
          .map((p) => ({
            id: p.id,
            kind: "person" as const,
            label: `${p.first_name} ${p.last_name}`,
            href: `/employees/${p.id}`,
            avatar: { firstName: p.first_name, lastName: p.last_name },
            absent: p.absent,
            badge: p.absent ? (p.absence_type ?? "Abwesend") : undefined,
            children: [],
          })),
      }));

    const vacancyNodes: ChartNode[] = (vacantOf.get(unit.id) ?? [])
      .filter((v) => !v.is_chief) // die Leitungsvakanz steht schon in der Kopfzeile
      .sort((a, b) => a.position_number.localeCompare(b.position_number))
      .map((v) => ({
        id: `vac-${v.position_id}`,
        kind: "vacancy" as const,
        label: `+ ${v.position_number} · ${v.job_title}`,
        href: "/positions",
        vacant: true,
        children: [],
      }));

    return {
      id: key,
      kind: "role",
      label: `${unit.org_number} · ${unit.name}`,
      sublabel: chief
        ? `Leitung: ${chief.first_name} ${chief.last_name}${chief.absent ? " (abwesend)" : ""}`
        : "Leitung vakant",
      vacant: !chief,
      children: [...subUnits, ...titleGroups, ...vacancyNodes],
    };
  }

  return (childUnits.get(null) ?? []).map(build);
}
