﻿"use client";

import Link from "next/link";
import { useParams } from "next/navigation";
import { FormEvent, useEffect, useMemo, useState } from "react";
import {
  copyGlobalDeviceToProject,
  copyDistributionBoard,
  copyProjectDeviceToGlobal,
  createDistributionBoard,
  createFloor,
  createProjectDevice,
  createRoom,
  deleteFloor,
  deleteProjectDevice,
  deleteRoom,
  deleteDistributionBoard,
  disconnectProjectDeviceRows,
  exportProjectTransfer,
  getProjectDeviceSyncPreview,
  listCircuitLists,
  listDistributionBoards,
  listFloors,
  listGlobalDevices,
  listProjectDevices,
  listProjects,
  listRooms,
  importProjectTransfer,
  synchronizeProjectDeviceRows,
  updateDistributionBoard,
  updateFloor,
  updateProjectDevice,
  updateProjectSettings,
  updateRoom,
} from "../../../frontend/utils/api";
import type {
  CircuitListDto,
  CreateProjectDeviceInput,
  DistributionBoardDto,
  FloorDto,
  GlobalDeviceDto,
  ProjectDeviceDto,
  ProjectDeviceSyncPreviewDto,
  ProjectDto,
  RoomDto,
} from "../../../frontend/types";
import {
  projectDeviceSyncFields,
  type ProjectDeviceSyncField,
} from "../../../shared/constants/project-device-sync-fields";
import {
  distributionBoardSupplyTypeLabels,
  type DistributionBoardSupplyType,
} from "../../../shared/constants/distribution-board";
import { ProjectVersionHistory } from "../../../frontend/components/project-version-history";
import {
  ProjectSettingsModal,
  type ProjectSettingsInput,
} from "../../../frontend/components/project-settings-modal";
import { FormModal } from "../../../frontend/components/form-modal";
import { ProjectDeviceModal } from "../../../frontend/components/project-device-modal";

const projectDeviceSyncFieldLabels: Record<ProjectDeviceSyncField, string> = {
  name: "Technischer Name",
  displayName: "Anzeigename",
  phaseType: "Phasenart",
  connectionKind: "Anschlussart",
  costGroup: "Kostengruppe",
  category: "Kategorie",
  quantity: "Anzahl",
  powerPerUnit: "Leistung je Stück",
  simultaneityFactor: "Gleichzeitigkeitsfaktor",
  cosPhi: "cos Phi",
  remark: "Bemerkung",
};

export default function ProjectDetailPage() {
  const params = useParams<{ projectId: string }>();
  const [projectId, setProjectId] = useState("");
  const [project, setProject] = useState<ProjectDto | null>(null);
  const [boards, setBoards] = useState<DistributionBoardDto[]>([]);
  const [circuitLists, setCircuitLists] = useState<CircuitListDto[]>([]);
  const [floors, setFloors] = useState<FloorDto[]>([]);
  const [rooms, setRooms] = useState<RoomDto[]>([]);
  const [projectDevices, setProjectDevices] = useState<ProjectDeviceDto[]>([]);
  const [globalDevices, setGlobalDevices] = useState<GlobalDeviceDto[]>([]);
  const [boardName, setBoardName] = useState("");
  const [boardFloorId, setBoardFloorId] = useState("");
  const [boardSupplyType, setBoardSupplyType] =
    useState<DistributionBoardSupplyType>("AV");
  const [editingBoard, setEditingBoard] =
    useState<DistributionBoardDto | null>(null);
  const [editingBoardFloorId, setEditingBoardFloorId] = useState("");
  const [editingBoardSupplyType, setEditingBoardSupplyType] =
    useState<DistributionBoardSupplyType>("AV");
  const [
    editingBoardSimultaneityFactor,
    setEditingBoardSimultaneityFactor,
  ] = useState("1");
  const [editingBoardCopyName, setEditingBoardCopyName] = useState("");
  const [floorName, setFloorName] = useState("");
  const [editingFloor, setEditingFloor] = useState<FloorDto | null>(null);
  const [roomNumber, setRoomNumber] = useState("");
  const [roomName, setRoomName] = useState("");
  const [roomFloorId, setRoomFloorId] = useState("");
  const [editingRoom, setEditingRoom] = useState<RoomDto | null>(null);
  const [isProjectSettingsOpen, setIsProjectSettingsOpen] = useState(false);
  const [structureModal, setStructureModal] = useState<
    "board" | "floor" | "room" | null
  >(null);
  const [isProjectDeviceModalOpen, setIsProjectDeviceModalOpen] =
    useState(false);
  const [editingProjectDevice, setEditingProjectDevice] =
    useState<ProjectDeviceDto | null>(null);
  const [projectDeviceQuery, setProjectDeviceQuery] = useState("");
  const [syncPreview, setSyncPreview] = useState<ProjectDeviceSyncPreviewDto | null>(null);
  const [selectedSyncRowIds, setSelectedSyncRowIds] = useState<string[]>([]);
  const [selectedSyncFields, setSelectedSyncFields] = useState<ProjectDeviceSyncField[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [isSaving, setIsSaving] = useState(false);

  useEffect(() => {
    setProjectId(params.projectId);
  }, [params.projectId]);

  useEffect(() => {
    if (!projectId) {
      return;
    }
    Promise.all([
      listProjects(),
      listDistributionBoards(projectId),
      listCircuitLists(projectId),
      listFloors(projectId),
      listRooms(projectId),
      listProjectDevices(projectId),
      listGlobalDevices(),
    ])
      .then(([
        projects,
        distributionBoards,
        loadedCircuitLists,
        loadedFloors,
        loadedRooms,
        loadedProjectDevices,
        loadedGlobalDevices,
      ]) => {
        const currentProject = projects.find((item) => item.id === projectId) ?? null;
        setProject(currentProject);
        setBoards(distributionBoards);
        setCircuitLists(loadedCircuitLists);
        setFloors(loadedFloors);
        setRooms(loadedRooms);
        setProjectDevices(loadedProjectDevices);
        setGlobalDevices(loadedGlobalDevices);
        setError(null);
      })
      .catch((err: unknown) =>
        setError(err instanceof Error ? err.message : "Projektdaten konnten nicht geladen werden.")
      );
  }, [projectId]);

  const boardCount = useMemo(() => boards.length, [boards.length]);
  const floorCount = useMemo(() => floors.length, [floors.length]);
  const roomCount = useMemo(() => rooms.length, [rooms.length]);
  const projectDeviceCount = useMemo(() => projectDevices.length, [projectDevices.length]);
  const visibleProjectDevices = useMemo(() => {
    const query = projectDeviceQuery.trim().toLocaleLowerCase("de");
    if (!query) {
      return projectDevices;
    }
    return projectDevices.filter((device) =>
      [
        device.name,
        device.displayName,
        device.category,
        device.connectionKind,
        device.costGroup,
      ].some((value) => value?.toLocaleLowerCase("de").includes(query))
    );
  }, [projectDeviceQuery, projectDevices]);
  const floorById = useMemo(() => new Map(floors.map((item) => [item.id, item])), [floors]);
  const circuitListByBoardId = useMemo(
    () => new Map(circuitLists.map((circuitList) => [circuitList.distributionBoardId, circuitList])),
    [circuitLists]
  );
  const enabledBoardSupplyTypes =
    project?.enabledDistributionBoardSupplyTypes ?? [];
  const usedBoardSupplyTypes = useMemo(
    () =>
      [
        ...new Set(
          boards
            .map((board) => board.supplyType)
            .filter(
              (
                supplyType
              ): supplyType is DistributionBoardSupplyType =>
                supplyType !== null
            )
        ),
      ],
    [boards]
  );

  function applyProjectRevision(currentRevision: number) {
    setProject((current) =>
      current ? { ...current, currentRevision } : current
    );
  }

  async function handleCreateBoard(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!projectId || !project || !boardName.trim()) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = await createDistributionBoard(
        projectId,
        {
          name: boardName.trim(),
          floorId: boardFloorId || null,
          supplyType: boardSupplyType,
        },
        project.currentRevision
      );
      setBoards((current) => [
        ...current,
        result.distributionBoard,
      ]);
      setCircuitLists(await listCircuitLists(projectId));
      applyProjectRevision(result.history.currentRevision);
      setBoardName("");
      setBoardFloorId("");
      setBoardSupplyType(
        project.enabledDistributionBoardSupplyTypes[0]
      );
      setStructureModal(null);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Verteilung konnte nicht erstellt werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleSaveFloor(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!projectId || !project || !floorName.trim()) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = editingFloor
        ? await updateFloor(
            projectId,
            editingFloor.id,
            { name: floorName.trim() },
            project.currentRevision
          )
        : await createFloor(
            projectId,
            { name: floorName.trim() },
            project.currentRevision
          );
      setFloors((current) =>
        editingFloor
          ? current.map((floor) =>
              floor.id === result.floor.id ? result.floor : floor
            )
          : [...current, result.floor]
      );
      applyProjectRevision(result.history.currentRevision);
      setFloorName("");
      setEditingFloor(null);
      setStructureModal(null);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Etage konnte nicht gespeichert werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleSaveRoom(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (
      !projectId ||
      !project ||
      !roomNumber.trim() ||
      !roomName.trim()
    ) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const input = {
        floorId: roomFloorId || undefined,
        roomNumber: roomNumber.trim(),
        roomName: roomName.trim(),
      };
      const result = editingRoom
        ? await updateRoom(
            projectId,
            editingRoom.id,
            input,
            project.currentRevision
          )
        : await createRoom(projectId, input, project.currentRevision);
      setRooms((current) =>
        editingRoom
          ? current.map((room) =>
              room.id === result.room.id ? result.room : room
            )
          : [...current, result.room]
      );
      applyProjectRevision(result.history.currentRevision);
      setRoomNumber("");
      setRoomName("");
      setRoomFloorId("");
      setEditingRoom(null);
      setStructureModal(null);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Raum konnte nicht gespeichert werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleSaveProjectSettings(input: ProjectSettingsInput) {
    if (!projectId || !project) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = await updateProjectSettings(
        projectId,
        project.currentRevision,
        input
      );
      setProject(result.project);
      setIsProjectSettingsOpen(false);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Projekteigenschaften konnten nicht gespeichert werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleCreateProjectDevice(
    payload: CreateProjectDeviceInput
  ) {
    if (!projectId || !project || !payload.name.trim()) {
      return;
    }

    setIsSaving(true);
    setError(null);
    try {
      const result = await createProjectDevice(
        projectId,
        payload,
        project.currentRevision
      );
      setProjectDevices((current) => [...current, result.projectDevice]);
      applyProjectRevision(result.history.currentRevision);
      setIsProjectDeviceModalOpen(false);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Projektgerät konnte nicht erstellt werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleDeleteProjectDevice(projectDeviceId: string) {
    if (!projectId || !project) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = await deleteProjectDevice(
        projectId,
        projectDeviceId,
        project.currentRevision
      );
      setProjectDevices((current) => current.filter((item) => item.id !== projectDeviceId));
      applyProjectRevision(result.history.currentRevision);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Projektgerät konnte nicht gelöscht werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleUpdateProjectDevice(
    device: ProjectDeviceDto,
    payload: CreateProjectDeviceInput
  ) {
    if (!projectId || !project) {
      return;
    }

    setIsSaving(true);
    setError(null);
    try {
      const result = await updateProjectDevice(
        projectId,
        device.id,
        payload,
        project.currentRevision
      );
      setProjectDevices((current) =>
        current.map((item) =>
          item.id === device.id ? result.projectDevice : item
        )
      );
      applyProjectRevision(result.history.currentRevision);
      setEditingProjectDevice(null);
      await openProjectDeviceSyncPreview(result.projectDevice.id);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Projektgerät konnte nicht aktualisiert werden.");
    } finally {
      setIsSaving(false);
    }
  }

  function openBoardEditor(board: DistributionBoardDto) {
    setEditingBoard(board);
    setEditingBoardFloorId(board.floorId ?? "");
    setEditingBoardSupplyType(
      board.supplyType ??
        project?.enabledDistributionBoardSupplyTypes[0] ??
        "AV"
    );
    setEditingBoardSimultaneityFactor(
      String(board.simultaneityFactor)
    );
    setEditingBoardCopyName(`${board.name} Kopie`);
  }

  function openBoardCreator() {
    setBoardSupplyType(
      project?.enabledDistributionBoardSupplyTypes[0] ?? "AV"
    );
    setStructureModal("board");
  }

  async function handleUpdateBoard(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!projectId || !project || !editingBoard) {
      return;
    }
    const simultaneityFactor = Number(
      editingBoardSimultaneityFactor
    );
    if (
      !editingBoardSimultaneityFactor.trim() ||
      !Number.isFinite(simultaneityFactor) ||
      simultaneityFactor < 0 ||
      simultaneityFactor > 1
    ) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = await updateDistributionBoard(
        projectId,
        editingBoard.id,
        {
          floorId: editingBoardFloorId || null,
          supplyType: editingBoardSupplyType,
          simultaneityFactor,
        },
        project.currentRevision
      );
      setBoards((current) =>
        current.map((board) =>
          board.id === result.distributionBoard.id
            ? result.distributionBoard
            : board
        )
      );
      applyProjectRevision(result.history.currentRevision);
      setEditingBoard(null);
    } catch (err) {
      setError(
        err instanceof Error
          ? err.message
          : "Verteilung konnte nicht bearbeitet werden."
      );
    } finally {
      setIsSaving(false);
    }
  }

  function openCreateFloor() {
    setEditingFloor(null);
    setFloorName("");
    setStructureModal("floor");
  }

  function openEditFloor(floor: FloorDto) {
    setEditingFloor(floor);
    setFloorName(floor.name);
    setStructureModal("floor");
  }

  function openCreateRoom() {
    setEditingRoom(null);
    setRoomNumber("");
    setRoomName("");
    setRoomFloorId("");
    setStructureModal("room");
  }

  function openEditRoom(room: RoomDto) {
    setEditingRoom(room);
    setRoomNumber(room.roomNumber);
    setRoomName(room.roomName);
    setRoomFloorId(room.floorId ?? "");
    setStructureModal("room");
  }

  async function handleDeleteFloor() {
    if (!projectId || !project || !editingFloor) return;
    if (!window.confirm(`Etage „${editingFloor.name}“ wirklich löschen?`)) return;
    setIsSaving(true);
    setError(null);
    try {
      const result = await deleteFloor(projectId, editingFloor.id, project.currentRevision);
      setFloors((current) => current.filter((floor) => floor.id !== editingFloor.id));
      applyProjectRevision(result.history.currentRevision);
      setEditingFloor(null);
      setFloorName("");
      setStructureModal(null);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Etage konnte nicht gelöscht werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleDeleteRoom() {
    if (!projectId || !project || !editingRoom) return;
    if (!window.confirm(`Raum „${editingRoom.roomNumber} ${editingRoom.roomName}“ wirklich löschen?`)) return;
    setIsSaving(true);
    setError(null);
    try {
      const result = await deleteRoom(projectId, editingRoom.id, project.currentRevision);
      setRooms((current) => current.filter((room) => room.id !== editingRoom.id));
      applyProjectRevision(result.history.currentRevision);
      setEditingRoom(null);
      setRoomNumber("");
      setRoomName("");
      setRoomFloorId("");
      setStructureModal(null);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Raum konnte nicht gelöscht werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleCopyBoard() {
    if (
      !projectId ||
      !project ||
      !editingBoard ||
      !editingBoardCopyName.trim()
    ) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = await copyDistributionBoard(
        projectId,
        editingBoard.id,
        editingBoardCopyName.trim(),
        project.currentRevision
      );
      setBoards((current) => [
        ...current,
        result.distributionBoard,
      ]);
      setCircuitLists((current) => [
        ...current,
        result.circuitList,
      ]);
      applyProjectRevision(result.history.currentRevision);
      setEditingBoard(null);
    } catch (err) {
      setError(
        err instanceof Error
          ? err.message
          : "Verteilung konnte nicht kopiert werden."
      );
    } finally {
      setIsSaving(false);
    }
  }

  async function handleDeleteBoard() {
    if (!projectId || !project || !editingBoard) {
      return;
    }
    const confirmed = window.confirm(
      `Verteilung „${editingBoard.name}“ wirklich löschen?\n\n` +
        "Dabei werden die Stromkreisliste, alle Gruppen, Stromkreise, Gerätezeilen, Schutzgeräte und weiteren Verteilergeräte entfernt. " +
        "Der Vorgang kann anschließend über die projektweite Historie rückgängig gemacht werden."
    );
    if (!confirmed) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = await deleteDistributionBoard(
        projectId,
        editingBoard.id,
        project.currentRevision
      );
      setBoards((current) =>
        current.filter((board) => board.id !== result.distributionBoardId)
      );
      setCircuitLists((current) =>
        current.filter(
          (circuitList) =>
            circuitList.distributionBoardId !==
            result.distributionBoardId
        )
      );
      applyProjectRevision(result.history.currentRevision);
      setEditingBoard(null);
    } catch (err) {
      setError(
        err instanceof Error
          ? err.message
          : "Verteilung konnte nicht gelöscht werden."
      );
    } finally {
      setIsSaving(false);
    }
  }

  async function handleExportProject() {
    if (!project) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const transfer = await exportProjectTransfer(project.id);
      const blob = new Blob([JSON.stringify(transfer, null, 2)], {
        type: "application/json",
      });
      const url = URL.createObjectURL(blob);
      const anchor = document.createElement("a");
      anchor.href = url;
      anchor.download = `${project.name.replace(/[^a-zA-Z0-9_-]+/g, "-") || "projekt"}.leistungsbilanz.json`;
      anchor.click();
      URL.revokeObjectURL(url);
    } catch (err) {
      setError(
        err instanceof Error
          ? err.message
          : "Projekt konnte nicht exportiert werden."
      );
    } finally {
      setIsSaving(false);
    }
  }

  async function handleImportProject(
    transfer: unknown,
    mode: "replace" | "duplicate"
  ) {
    if (!project) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = await importProjectTransfer(
        project.id,
        mode,
        project.currentRevision,
        transfer
      );
      if (mode === "duplicate" && "projectId" in result) {
        window.location.href = `/projects/${result.projectId}`;
        return;
      }
      window.location.reload();
    } catch (err) {
      setError(
        err instanceof Error
          ? err.message
          : "Projektdatei konnte nicht importiert werden."
      );
      setIsProjectSettingsOpen(false);
    } finally {
      setIsSaving(false);
    }
  }

  async function openProjectDeviceSyncPreview(projectDeviceId: string) {
    if (!projectId) {
      return;
    }
    try {
      const preview = await getProjectDeviceSyncPreview(projectId, projectDeviceId);
      setSyncPreview(preview);
      setSelectedSyncRowIds(preview.rows.filter((row) => row.differences.length > 0).map((row) => row.rowId));
      const differentFields = new Set(
        preview.rows.flatMap((row) => row.differences.map((difference) => difference.field))
      );
      setSelectedSyncFields(
        projectDeviceSyncFields.filter((field) => field !== "displayName" && differentFields.has(field))
      );
    } catch (err) {
      setError(err instanceof Error ? err.message : "Verknüpfungen konnten nicht geladen werden.");
    }
  }

  function toggleSyncRow(rowId: string) {
    setSelectedSyncRowIds((current) =>
      current.includes(rowId) ? current.filter((id) => id !== rowId) : [...current, rowId]
    );
  }

  function toggleSyncField(field: ProjectDeviceSyncField) {
    setSelectedSyncFields((current) =>
      current.includes(field) ? current.filter((entry) => entry !== field) : [...current, field]
    );
  }

  async function handleSynchronizeProjectDeviceRows() {
    if (
      !projectId ||
      !project ||
      !syncPreview ||
      selectedSyncRowIds.length === 0 ||
      selectedSyncFields.length === 0
    ) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = await synchronizeProjectDeviceRows(
        projectId,
        syncPreview.projectDevice.id,
        selectedSyncRowIds,
        selectedSyncFields,
        project.currentRevision
      );
      setSyncPreview(result.preview);
      applyProjectRevision(result.history.currentRevision);
      setSelectedSyncRowIds(
        result.preview.rows.filter((row) => row.differences.length > 0).map((row) => row.rowId)
      );
    } catch (err) {
      setError(err instanceof Error ? err.message : "Gerätezeilen konnten nicht synchronisiert werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleDisconnectProjectDeviceRows() {
    if (
      !projectId ||
      !project ||
      !syncPreview ||
      selectedSyncRowIds.length === 0
    ) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const result = await disconnectProjectDeviceRows(
        projectId,
        syncPreview.projectDevice.id,
        selectedSyncRowIds,
        project.currentRevision
      );
      setSyncPreview(result.preview);
      setSelectedSyncRowIds(
        result.preview.rows
          .filter((row) => row.differences.length > 0)
          .map((row) => row.rowId)
      );
      applyProjectRevision(result.history.currentRevision);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Verknüpfungen konnten nicht getrennt werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleCopyGlobalToProject(globalDeviceId: string) {
    if (!projectId || !project || !globalDeviceId) {
      return;
    }

    setIsSaving(true);
    setError(null);
    try {
      const result = await copyGlobalDeviceToProject(
        projectId,
        globalDeviceId,
        project.currentRevision
      );
      setProjectDevices((current) => [...current, result.projectDevice]);
      applyProjectRevision(result.history.currentRevision);
      setIsProjectDeviceModalOpen(false);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Globales Gerät konnte nicht ins Projekt kopiert werden.");
    } finally {
      setIsSaving(false);
    }
  }

  async function handleCopyProjectToGlobal(projectDeviceId: string) {
    if (!projectId) {
      return;
    }

    setIsSaving(true);
    setError(null);
    try {
      const created = await copyProjectDeviceToGlobal(projectId, projectDeviceId);
      setGlobalDevices((current) => [...current, created]);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Projektgerät konnte nicht global kopiert werden.");
    } finally {
      setIsSaving(false);
    }
  }

  return (
    <main className="container py-4">
      <div className="page-header">
        <div>
          <div className="kicker">Projekt</div>
          <h1>{project?.name ?? "Projekt"}</h1>
          <p className="text-secondary mb-0">
            {project?.internalProjectNumber
              ? `Projektnummer ${project.internalProjectNumber} · `
              : ""}
            Verteilerübersicht und Einstieg in die Stromkreislisten
          </p>
        </div>
        <div className="d-flex gap-2">
          <button
            className="btn btn-outline-primary"
            disabled={!project}
            onClick={() => setIsProjectSettingsOpen(true)}
            type="button"
          >
            Projekteinstellungen
          </button>
          <Link className="btn btn-outline-secondary" href="/projects">
            Zur Projektübersicht
          </Link>
        </div>
      </div>

      {error ? <div className="alert alert-warning">{error}</div> : null}

      <div className="kpi-grid">
        <a className="kpi" href="#verteilungen">
          <div className="kpi-label">Verteilungen</div>
          <div className="kpi-value">{boardCount}</div>
        </a>
        <a className="kpi" href="#etagen">
          <div className="kpi-label">Etagen</div>
          <div className="kpi-value">{floorCount}</div>
        </a>
        <a className="kpi" href="#raeume">
          <div className="kpi-label">Räume</div>
          <div className="kpi-value">{roomCount}</div>
        </a>
        <a className="kpi" href="#projektgeraete">
          <div className="kpi-label">Projektgeräte</div>
          <div className="kpi-value">{projectDeviceCount}</div>
        </a>
      </div>

      <div className="row g-4">
        {project ? (
          <section className="col-12" id="verlauf">
            <ProjectVersionHistory
              currentRevision={project.currentRevision}
              onProjectStateChange={() => window.location.reload()}
              projectId={projectId}
            />
          </section>
        ) : null}

        <section className="col-12" id="verteilungen">
          <div className="card shadow-sm">
            <div className="card-header d-flex justify-content-between align-items-center">
              <div>
                <span>Verteilungen</span>
                <span className="badge text-bg-secondary ms-2">{boardCount}</span>
              </div>
              <button
                className="btn btn-sm btn-primary"
                onClick={openBoardCreator}
                type="button"
              >
                Verteilung hinzufügen
              </button>
            </div>
            <div className="table-responsive">
              <table className="table table-hover align-middle mb-0">
                <thead>
                  <tr>
                    <th>Verteilung</th>
                    <th>Etage</th>
                    <th>Netzart</th>
                    <th>GZF</th>
                    <th className="text-end">Aktionen</th>
                  </tr>
                </thead>
                <tbody>
                  {boards.map((board) => {
                    const circuitList = circuitListByBoardId.get(board.id);
                    return (
                      <tr key={board.id}>
                        <td>{board.name}</td>
                        <td>
                          {board.floorId
                            ? floorById.get(board.floorId)?.name ?? "Unbekannt"
                            : "Ohne Etage"}
                        </td>
                        <td>
                          {board.supplyType
                            ? distributionBoardSupplyTypeLabels[
                                board.supplyType
                              ]
                            : "Nicht festgelegt"}
                        </td>
                        <td>
                          {board.simultaneityFactor.toLocaleString(
                            "de-DE",
                            {
                              minimumFractionDigits: 2,
                              maximumFractionDigits: 2,
                            }
                          )}
                        </td>
                        <td className="text-end">
                          <div className="d-inline-flex flex-wrap justify-content-end gap-2">
                            <button
                              className="btn btn-sm btn-outline-secondary"
                              disabled={isSaving}
                              onClick={() => openBoardEditor(board)}
                              type="button"
                            >
                              Bearbeiten
                            </button>
                            {circuitList ? (
                              <Link
                                className="btn btn-sm btn-primary"
                                href={`/projects/${projectId}/circuit-lists/${circuitList.id}/tree-edit`}
                              >
                                Stromkreisliste öffnen
                              </Link>
                            ) : (
                              <span className="text-secondary small align-self-center">
                                Keine Stromkreisliste vorhanden
                              </span>
                            )}
                          </div>
                        </td>
                      </tr>
                    );
                  })}
                  {!boards.length ? (
                    <tr>
                      <td colSpan={5} className="text-center text-secondary py-4">
                        Noch keine Verteilungen vorhanden.
                      </td>
                    </tr>
                  ) : null}
                </tbody>
              </table>
            </div>
          </div>
        </section>

        <section className="col-12 col-lg-5" id="etagen">
          <div className="card shadow-sm h-100">
            <div className="card-header d-flex justify-content-between align-items-center">
              <div>
                <span>Etagen</span>
                <span className="badge text-bg-secondary ms-2">{floorCount}</span>
              </div>
              <button
                className="btn btn-sm btn-outline-primary"
                onClick={openCreateFloor}
                type="button"
              >
                Hinzufügen
              </button>
            </div>
            <ul className="list-group list-group-flush">
              {floors.map((floor) => (
                <li className="list-group-item d-flex justify-content-between align-items-center gap-2" key={floor.id}>
                  <span>{floor.name}</span>
                  <button className="btn btn-sm btn-outline-secondary" onClick={() => openEditFloor(floor)} type="button">
                    Bearbeiten
                  </button>
                </li>
              ))}
              {!floors.length ? (
                <li className="list-group-item text-secondary">Noch keine Etagen vorhanden.</li>
              ) : null}
            </ul>
          </div>
        </section>

        <section className="col-12 col-lg-7" id="raeume">
          <div className="card shadow-sm">
            <div className="card-header d-flex justify-content-between align-items-center">
              <div>
                <span>Räume</span>
                <span className="badge text-bg-secondary ms-2">{roomCount}</span>
              </div>
              <button
                className="btn btn-sm btn-outline-primary"
                onClick={openCreateRoom}
                type="button"
              >
                Hinzufügen
              </button>
            </div>
            <div className="table-responsive">
              <table className="table table-hover align-middle mb-0">
                <thead>
                  <tr>
                    <th>Raumnummer</th>
                    <th>Raumname</th>
                    <th>Etage</th>
                    <th className="text-end">Aktionen</th>
                  </tr>
                </thead>
                <tbody>
                  {rooms.map((room) => (
                    <tr key={room.id}>
                      <td>{room.roomNumber}</td>
                      <td>{room.roomName}</td>
                      <td>{room.floorId ? floorById.get(room.floorId)?.name ?? "-" : "-"}</td>
                      <td className="text-end">
                        <button className="btn btn-sm btn-outline-secondary" onClick={() => openEditRoom(room)} type="button">
                          Bearbeiten
                        </button>
                      </td>
                    </tr>
                  ))}
                  {!rooms.length ? (
                    <tr>
                      <td colSpan={4} className="text-center text-secondary py-4">
                        Noch keine Räume vorhanden.
                      </td>
                    </tr>
                  ) : null}
                </tbody>
              </table>
            </div>
          </div>
        </section>
      </div>

      <section className="card shadow-sm mt-4" id="projektgeraete">
        <div className="card-header d-flex flex-wrap justify-content-between align-items-center gap-2">
          <div>
            <span>Projektgeräte</span>
            <span className="badge text-bg-secondary ms-2">{projectDeviceCount}</span>
          </div>
          <div className="d-flex gap-2">
            <input
              aria-label="Projektgeräte durchsuchen"
              className="form-control form-control-sm"
              onChange={(event) => setProjectDeviceQuery(event.target.value)}
              placeholder="Geräte durchsuchen"
              type="search"
              value={projectDeviceQuery}
            />
            <button
              className="btn btn-sm btn-primary text-nowrap"
              onClick={() => setIsProjectDeviceModalOpen(true)}
              type="button"
            >
              Gerät hinzufügen
            </button>
          </div>
        </div>
        <div className="table-responsive">
          <table className="table table-sm table-striped align-middle mb-0">
            <thead>
              <tr>
                <th>Gerät</th>
                <th>Anschluss</th>
                <th>Leistung</th>
                <th>Kostengruppe</th>
                <th className="text-end">Aktionen</th>
              </tr>
            </thead>
            <tbody>
              {visibleProjectDevices.map((device) => (
                <tr key={device.id}>
                  <td>
                    <strong>{device.displayName}</strong>
                    <div className="small text-secondary">
                      {device.name}
                      {device.category ? ` · ${device.category}` : ""}
                    </div>
                  </td>
                  <td>
                    {device.phaseType === "three_phase" ? "3-phasig" : "1-phasig"}
                    {device.connectionKind ? (
                      <div className="small text-secondary">
                        {device.connectionKind}
                      </div>
                    ) : null}
                  </td>
                  <td>
                    {device.totalPower} kW
                    <div className="small text-secondary">
                      {device.quantity} × {device.powerPerUnit} kW · GZF{" "}
                      {device.simultaneityFactor}
                    </div>
                  </td>
                  <td>{device.costGroup ?? "-"}</td>
                  <td className="text-end">
                    <div className="d-inline-flex flex-wrap justify-content-end gap-1">
                      <button
                        className="btn btn-sm btn-outline-secondary"
                        type="button"
                        onClick={() => setEditingProjectDevice(device)}
                        disabled={isSaving}
                      >
                        Bearbeiten
                      </button>
                      <button
                        className="btn btn-sm btn-outline-primary"
                        type="button"
                        onClick={() => void openProjectDeviceSyncPreview(device.id)}
                        disabled={isSaving}
                      >
                        Verknüpfungen
                      </button>
                      <button
                        className="btn btn-sm btn-outline-secondary"
                        type="button"
                        onClick={() => handleCopyProjectToGlobal(device.id)}
                        disabled={isSaving}
                      >
                        Nach global kopieren
                      </button>
                      <button
                        className="btn btn-sm btn-outline-danger"
                        type="button"
                        onClick={() => handleDeleteProjectDevice(device.id)}
                        disabled={isSaving}
                      >
                        Löschen
                      </button>
                    </div>
                  </td>
                </tr>
              ))}
              {!visibleProjectDevices.length ? (
                <tr>
                  <td colSpan={5} className="text-center text-secondary py-4">
                    {projectDevices.length
                      ? "Keine Projektgeräte entsprechen der Suche."
                      : "Noch keine Projektgeräte vorhanden."}
                  </td>
                </tr>
              ) : null}
            </tbody>
          </table>
        </div>
        {syncPreview ? (
          <div className="card-body border-top">
            <div className="d-flex flex-wrap justify-content-between align-items-start gap-2 mb-3">
              <div>
                <h3 className="h6 mb-1">Verknüpfte Zeilen: {syncPreview.projectDevice.displayName}</h3>
                <p className="text-secondary small mb-0">
                  Nur ausgewählte Felder und Zeilen werden übernommen. Der Anzeigename bleibt standardmäßig lokal.
                </p>
              </div>
              <button className="btn btn-sm btn-outline-secondary" type="button" onClick={() => setSyncPreview(null)}>
                Schließen
              </button>
            </div>

            <div className="d-flex flex-wrap gap-3 mb-3">
              {projectDeviceSyncFields.map((field) => (
                <label className="form-check" key={field}>
                  <input
                    className="form-check-input"
                    type="checkbox"
                    checked={selectedSyncFields.includes(field)}
                    onChange={() => toggleSyncField(field)}
                  />
                  <span className="form-check-label">
                    {projectDeviceSyncFieldLabels[field]}
                    {field === "displayName" ? " (lokal)" : ""}
                  </span>
                </label>
              ))}
            </div>

            <div className="table-responsive border rounded mb-3">
              <table className="table table-sm align-middle mb-0">
                <thead>
                  <tr>
                    <th>Auswahl</th>
                    <th>Verteilung / Stromkreis</th>
                    <th>Gerätezeile</th>
                    <th>Abweichungen</th>
                  </tr>
                </thead>
                <tbody>
                  {syncPreview.rows.map((row) => (
                    <tr key={row.rowId}>
                      <td>
                        <input
                          className="form-check-input"
                          type="checkbox"
                          checked={selectedSyncRowIds.includes(row.rowId)}
                          onChange={() => toggleSyncRow(row.rowId)}
                        />
                      </td>
                      <td>
                        <strong>{row.distributionBoardName}</strong>
                        <div className="small text-secondary">
                          {row.equipmentIdentifier}
                          {row.circuitDisplayName ? ` – ${row.circuitDisplayName}` : ""}
                        </div>
                      </td>
                      <td>{row.rowDisplayName}</td>
                      <td>
                        <div className="d-flex flex-wrap gap-1">
                          {row.differences.map((difference) => (
                            <span
                              className={`badge ${difference.isOverridden ? "text-bg-warning" : "text-bg-light"}`}
                              key={difference.field}
                              title={difference.isOverridden ? "Lokal überschrieben" : undefined}
                            >
                              {projectDeviceSyncFieldLabels[difference.field]}: {String(difference.currentValue ?? "–")} →{" "}
                              {String(difference.sourceValue ?? "–")}
                            </span>
                          ))}
                          {row.differences.length === 0 ? (
                            <span className="text-success small">Aktuell</span>
                          ) : null}
                        </div>
                      </td>
                    </tr>
                  ))}
                  {syncPreview.rows.length === 0 ? (
                    <tr>
                      <td colSpan={4} className="text-center text-secondary py-3">
                        Keine verknüpften Gerätezeilen im neuen Stromkreismodell vorhanden.
                      </td>
                    </tr>
                  ) : null}
                </tbody>
              </table>
            </div>

            <div className="d-flex flex-wrap gap-2">
              <button
                className="btn btn-primary"
                type="button"
                onClick={() => void handleSynchronizeProjectDeviceRows()}
                disabled={isSaving || selectedSyncRowIds.length === 0 || selectedSyncFields.length === 0}
              >
                Auswahl synchronisieren
              </button>
              <button
                className="btn btn-outline-danger"
                type="button"
                onClick={() => void handleDisconnectProjectDeviceRows()}
                disabled={isSaving || selectedSyncRowIds.length === 0}
              >
                Auswahl trennen
              </button>
            </div>
          </div>
        ) : null}
      </section>

      {structureModal === "board" ? (
        <FormModal
          description="Eine Stromkreisliste mit den drei Standardgruppen wird automatisch angelegt."
          isSaving={isSaving}
          onClose={() => setStructureModal(null)}
          onSubmit={handleCreateBoard}
          submitDisabled={!boardName.trim()}
          submitLabel="Verteilung erstellen"
          title="Verteilung hinzufügen"
        >
          <label className="form-label" htmlFor="distribution-board-name">
            Bezeichnung
          </label>
          <input
            autoFocus
            className="form-control"
            id="distribution-board-name"
            onChange={(event) => setBoardName(event.target.value)}
            placeholder="z. B. UV-01"
            required
            value={boardName}
          />
          <div className="row g-3 mt-0">
            <div className="col-12 col-md-6">
              <label className="form-label" htmlFor="distribution-board-floor">
                Etage
              </label>
              <select
                className="form-select"
                id="distribution-board-floor"
                onChange={(event) => setBoardFloorId(event.target.value)}
                value={boardFloorId}
              >
                <option value="">Ohne Etage</option>
                {floors.map((floor) => (
                  <option key={floor.id} value={floor.id}>
                    {floor.name}
                  </option>
                ))}
              </select>
            </div>
            <div className="col-12 col-md-6">
              <label
                className="form-label"
                htmlFor="distribution-board-supply-type"
              >
                Netzart
              </label>
              <select
                className="form-select"
                id="distribution-board-supply-type"
                onChange={(event) =>
                  setBoardSupplyType(
                    event.target.value as DistributionBoardSupplyType
                  )
                }
                value={boardSupplyType}
              >
                {enabledBoardSupplyTypes.map((supplyType) => (
                    <option key={supplyType} value={supplyType}>
                      {distributionBoardSupplyTypeLabels[supplyType]}
                    </option>
                  ))}
              </select>
            </div>
          </div>
        </FormModal>
      ) : null}

      {editingBoard ? (
        <FormModal
          description={`${editingBoard.name}: Etagenzuordnung, Netzart und Gleichzeitigkeitsfaktor ändern.`}
          isSaving={isSaving}
          onClose={() => setEditingBoard(null)}
          onSubmit={handleUpdateBoard}
          submitDisabled={
            !editingBoardSimultaneityFactor.trim() ||
            !Number.isFinite(
              Number(editingBoardSimultaneityFactor)
            ) ||
            Number(editingBoardSimultaneityFactor) < 0 ||
            Number(editingBoardSimultaneityFactor) > 1
          }
          submitLabel="Änderungen speichern"
          title="Verteilung bearbeiten"
        >
          <div className="row g-3">
            <div className="col-12 col-md-6">
              <label
                className="form-label"
                htmlFor="edit-distribution-board-floor"
              >
                Etage
              </label>
              <select
                autoFocus
                className="form-select"
                id="edit-distribution-board-floor"
                onChange={(event) =>
                  setEditingBoardFloorId(event.target.value)
                }
                value={editingBoardFloorId}
              >
                <option value="">Ohne Etage</option>
                {floors.map((floor) => (
                  <option key={floor.id} value={floor.id}>
                    {floor.name}
                  </option>
                ))}
              </select>
            </div>
            <div className="col-12 col-md-6">
              <label
                className="form-label"
                htmlFor="edit-distribution-board-supply-type"
              >
                Netzart
              </label>
              <select
                className="form-select"
                id="edit-distribution-board-supply-type"
                onChange={(event) =>
                  setEditingBoardSupplyType(
                    event.target.value as DistributionBoardSupplyType
                  )
                }
                value={editingBoardSupplyType}
              >
                {enabledBoardSupplyTypes.map((supplyType) => (
                    <option key={supplyType} value={supplyType}>
                      {distributionBoardSupplyTypeLabels[supplyType]}
                    </option>
                  ))}
              </select>
            </div>
            <div className="col-12 col-md-6">
              <label
                className="form-label"
                htmlFor="edit-distribution-board-simultaneity-factor"
              >
                Verteilerweiter Gleichzeitigkeitsfaktor
              </label>
              <input
                className="form-control"
                id="edit-distribution-board-simultaneity-factor"
                max="1"
                min="0"
                onChange={(event) =>
                  setEditingBoardSimultaneityFactor(
                    event.target.value
                  )
                }
                required
                step="0.01"
                type="number"
                value={editingBoardSimultaneityFactor}
              />
              <div className="form-text">
                Wird auf die Gesamtleistung des Verteilers angewendet.
              </div>
            </div>
          </div>
          <hr className="my-4" />
          <section aria-labelledby="copy-distribution-board-heading">
            <h3
              className="h6"
              id="copy-distribution-board-heading"
            >
              Verteilung kopieren
            </h3>
            <p className="text-secondary small">
              Erstellt eine vollständige Kopie des zuletzt gespeicherten
              Stands einschließlich Gruppen, Stromkreisen, Gerätezeilen und
              Schutzgeräten. Noch nicht gespeicherte Änderungen oben werden
              nicht übernommen.
            </p>
            <div className="row g-2 align-items-end">
              <div className="col-12 col-md">
                <label
                  className="form-label"
                  htmlFor="copy-distribution-board-name"
                >
                  Bezeichnung der Kopie
                </label>
                <input
                  className="form-control"
                  id="copy-distribution-board-name"
                  maxLength={200}
                  onChange={(event) =>
                    setEditingBoardCopyName(event.target.value)
                  }
                  value={editingBoardCopyName}
                />
              </div>
              <div className="col-12 col-md-auto">
                <button
                  className="btn btn-outline-primary"
                  disabled={isSaving || !editingBoardCopyName.trim()}
                  onClick={() => void handleCopyBoard()}
                  type="button"
                >
                  Verteilung kopieren
                </button>
              </div>
            </div>
          </section>
          <hr className="my-4" />
          <section
            aria-labelledby="delete-distribution-board-heading"
            className="border border-danger-subtle rounded p-3"
          >
            <h3
              className="h6 text-danger"
              id="delete-distribution-board-heading"
            >
              Gefahrenbereich
            </h3>
            <p className="text-secondary small mb-3">
              Entfernt die vollständige Verteilung. Die Aktion wird erst
              nach einer ausdrücklichen Warnung ausgeführt und kann über die
              projektweite Historie rückgängig gemacht werden.
            </p>
            <button
              className="btn btn-outline-danger"
              disabled={isSaving}
              onClick={() => void handleDeleteBoard()}
              type="button"
            >
              Verteilung löschen
            </button>
          </section>
        </FormModal>
      ) : null}

      {structureModal === "floor" ? (
        <FormModal
          isSaving={isSaving}
          onClose={() => {
            setStructureModal(null);
            setEditingFloor(null);
          }}
          onSubmit={handleSaveFloor}
          submitDisabled={!floorName.trim()}
          submitLabel={editingFloor ? "Änderungen speichern" : "Etage hinzufügen"}
          title={editingFloor ? "Etage bearbeiten" : "Etage hinzufügen"}
        >
          <label className="form-label" htmlFor="floor-name">
            Bezeichnung
          </label>
          <input
            autoFocus
            className="form-control"
            id="floor-name"
            onChange={(event) => setFloorName(event.target.value)}
            placeholder="z. B. EG"
            required
            value={floorName}
          />
          {editingFloor ? (
            <div className="border-top mt-4 pt-3">
              <p className="text-secondary small mb-2">
                Etagen mit zugeordneten Räumen oder Verteilungen können nicht gelöscht werden.
              </p>
              <button className="btn btn-outline-danger" disabled={isSaving} onClick={() => void handleDeleteFloor()} type="button">
                Etage löschen
              </button>
            </div>
          ) : null}
        </FormModal>
      ) : null}

      {structureModal === "room" ? (
        <FormModal
          isSaving={isSaving}
          onClose={() => {
            setStructureModal(null);
            setEditingRoom(null);
          }}
          onSubmit={handleSaveRoom}
          submitDisabled={!roomNumber.trim() || !roomName.trim()}
          submitLabel={editingRoom ? "Änderungen speichern" : "Raum anlegen"}
          title={editingRoom ? "Raum bearbeiten" : "Raum hinzufügen"}
        >
          <div className="row g-3">
            <div className="col-12 col-md-4">
              <label className="form-label" htmlFor="room-number">
                Raumnummer
              </label>
              <input
                autoFocus
                className="form-control"
                id="room-number"
                onChange={(event) => setRoomNumber(event.target.value)}
                required
                value={roomNumber}
              />
            </div>
            <div className="col-12 col-md-8">
              <label className="form-label" htmlFor="room-name">
                Raumname
              </label>
              <input
                className="form-control"
                id="room-name"
                onChange={(event) => setRoomName(event.target.value)}
                required
                value={roomName}
              />
            </div>
            <div className="col-12">
              <label className="form-label" htmlFor="room-floor">
                Etage
              </label>
              <select
                className="form-select"
                id="room-floor"
                onChange={(event) => setRoomFloorId(event.target.value)}
                value={roomFloorId}
              >
                <option value="">Ohne Etage</option>
                {floors.map((floor) => (
                  <option key={floor.id} value={floor.id}>
                    {floor.name}
                  </option>
                ))}
              </select>
            </div>
          </div>
          {editingRoom ? (
            <div className="border-top mt-4 pt-3">
              <p className="text-secondary small mb-2">
                In Stromkreisen verwendete Räume können nicht gelöscht werden.
              </p>
              <button className="btn btn-outline-danger" disabled={isSaving} onClick={() => void handleDeleteRoom()} type="button">
                Raum löschen
              </button>
            </div>
          ) : null}
        </FormModal>
      ) : null}

      {isProjectDeviceModalOpen ? (
        <ProjectDeviceModal
          globalDevices={globalDevices}
          isSaving={isSaving}
          onClose={() => setIsProjectDeviceModalOpen(false)}
          onImportGlobal={handleCopyGlobalToProject}
          onSave={handleCreateProjectDevice}
        />
      ) : null}

      {editingProjectDevice ? (
        <ProjectDeviceModal
          globalDevices={globalDevices}
          initialDevice={editingProjectDevice}
          isSaving={isSaving}
          onClose={() => setEditingProjectDevice(null)}
          onImportGlobal={handleCopyGlobalToProject}
          onSave={(input) =>
            handleUpdateProjectDevice(editingProjectDevice, input)
          }
        />
      ) : null}

      {project && isProjectSettingsOpen ? (
        <ProjectSettingsModal
          isSaving={isSaving}
          onClose={() => setIsProjectSettingsOpen(false)}
          onExport={handleExportProject}
          onImport={handleImportProject}
          onSave={handleSaveProjectSettings}
          project={project}
          usedDistributionBoardSupplyTypes={usedBoardSupplyTypes}
        />
      ) : null}
    </main>
  );
}


