// frontend\src\pages\operations\milestone-cameras\MilestoneCamerasPage.tsx

import { useEffect, useState } from "react";
import {
  MicrophoneIcon,
  VideoCameraIcon,
} from "@heroicons/react/24/outline";
import { MagnifyingGlassIcon } from "@heroicons/react/20/solid";
import LoadingSpinner from "../../../components/LoadingSpinner";
import Tables, { type TableColumn } from "../../../components/Tables";
import { Badge } from "../../../components/Badge";
import EmptyState from "../../../components/EmptyState";
import { useNotifications } from "../../../components/Notifications";

const API_URL = import.meta.env.VITE_API_URL ?? "http://localhost:8080";

type MilestoneCameraListItem = {
  id: string;
  name: string;
  displayName: string;
  type: "camera" | "microphone";
  enabled: boolean;
  recordingEnabled: boolean;
  recordingStorageId: string;
  hardwareId: string;
};

type StorageSimple = {
  id: string;
  name: string;
  displayName: string;
};

type Props = {
  canWrite?: boolean;
};

export default function MilestoneCamerasPage({ canWrite }: Props) {
  const { notify } = useNotifications();
  const [devices, setDevices] = useState<MilestoneCameraListItem[]>([]);
  const [storageMap, setStorageMap] = useState<Record<string, StorageSimple>>({});
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [search, setSearch] = useState("");

  useEffect(() => {
    void Promise.all([loadDevices(), loadStorages()]);
  }, []);

  async function loadDevices() {
    setIsLoading(true);
    setError(null);
    try {
      const response = await fetch(`${API_URL}/admin/milestone/cameras`, {
        credentials: "include",
      });
      if (!response.ok) {
        const data = (await response.json().catch(() => null)) as {
          error?: string;
        } | null;
        setError(data?.error ?? "Geräte konnten nicht geladen werden");
        return;
      }
      const data = (await response.json()) as {
        devices: MilestoneCameraListItem[];
      };
      setDevices(data.devices ?? []);
    } catch {
      setError("Verbindung zum Server fehlgeschlagen");
    } finally {
      setIsLoading(false);
    }
  }

  async function loadStorages() {
    try {
      const response = await fetch(`${API_URL}/admin/milestone/storages`, {
        credentials: "include",
      });
      if (!response.ok) return;
      const data = (await response.json()) as {
        storages?: { id: string; name: string; displayName: string }[];
      };
      const map: Record<string, StorageSimple> = {};
      for (const s of data.storages ?? []) {
        map[s.id] = { id: s.id, name: s.name, displayName: s.displayName };
      }
      setStorageMap(map);
    } catch {
      // silent – storage names are cosmetic
    }
  }

  async function handleToggle(
    device: MilestoneCameraListItem,
    field: "enabled" | "recordingEnabled",
  ) {
    const newValue = !device[field];

    setDevices((current) =>
      current.map((d) =>
        d.id === device.id ? { ...d, [field]: newValue } : d,
      ),
    );

    const collection = device.type === "camera" ? "cameras" : "microphones";
    try {
      const response = await fetch(
        `${API_URL}/admin/milestone/devices/${collection}/${device.id}`,
        {
          method: "PATCH",
          credentials: "include",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ [field]: newValue }),
        },
      );
      if (!response.ok) {
        const data = (await response.json().catch(() => null)) as {
          error?: string;
        } | null;
        setDevices((current) =>
          current.map((d) =>
            d.id === device.id ? { ...d, [field]: !newValue } : d,
          ),
        );
        notify.error(data?.error ?? "Gerät konnte nicht aktualisiert werden");
      }
    } catch {
      setDevices((current) =>
        current.map((d) =>
          d.id === device.id ? { ...d, [field]: !newValue } : d,
        ),
      );
      notify.error("Verbindung fehlgeschlagen");
    }
  }

  const searchLower = search.trim().toLowerCase();
  const filtered = searchLower
    ? devices.filter(
        (d) =>
          d.name.toLowerCase().includes(searchLower) ||
          d.displayName.toLowerCase().includes(searchLower),
      )
    : devices;

  const cameraCount = filtered.filter((d) => d.type === "camera").length;
  const micCount = filtered.filter((d) => d.type === "microphone").length;

  const columns: TableColumn<MilestoneCameraListItem>[] = [
    {
      key: "name",
      header: "Name",
      isPrimary: true,
      render: (row) => (
        <div className="flex items-center gap-2">
          {row.type === "camera" ? (
            <VideoCameraIcon className="size-4 shrink-0 text-gray-400" />
          ) : (
            <MicrophoneIcon className="size-4 shrink-0 text-gray-400" />
          )}
          <div>
            <div className="font-medium text-gray-900 dark:text-white">
              {row.name}
            </div>
            {row.displayName && row.displayName !== row.name && (
              <div className="text-xs text-gray-500 dark:text-gray-400">
                {row.displayName}
              </div>
            )}
          </div>
        </div>
      ),
    },
    {
      key: "enabled",
      header: "Status",
      hideOnMobile: "sm",
      render: (row) =>
        canWrite ? (
          <button
            type="button"
            onClick={(e) => {
              e.stopPropagation();
              void handleToggle(row, "enabled");
            }}
            className="cursor-pointer"
          >
            <Badge tone={row.enabled ? "green" : "gray"} hover>
              {row.enabled ? "Aktiv" : "Inaktiv"}
            </Badge>
          </button>
        ) : (
          <Badge tone={row.enabled ? "green" : "gray"}>
            {row.enabled ? "Aktiv" : "Inaktiv"}
          </Badge>
        ),
    },
    {
      key: "recordingEnabled",
      header: "Aufnahme",
      hideOnMobile: "md",
      render: (row) =>
        canWrite ? (
          <button
            type="button"
            onClick={(e) => {
              e.stopPropagation();
              void handleToggle(row, "recordingEnabled");
            }}
            className="cursor-pointer"
          >
            <Badge tone={row.recordingEnabled ? "indigo" : "gray"} hover>
              {row.recordingEnabled ? "Aktiv" : "Inaktiv"}
            </Badge>
          </button>
        ) : (
          <Badge tone={row.recordingEnabled ? "indigo" : "gray"}>
            {row.recordingEnabled ? "Aktiv" : "Inaktiv"}
          </Badge>
        ),
    },
    {
      key: "recordingStorageId",
      header: "Speicher",
      hideOnMobile: "lg",
      render: (row) => {
        const storage = storageMap[row.recordingStorageId];
        if (storage) {
          return (
            <span className="text-sm text-gray-700 dark:text-gray-300">
              {storage.displayName || storage.name}
            </span>
          );
        }
        if (row.recordingStorageId) {
          return (
            <span className="font-mono text-xs text-gray-400">
              {row.recordingStorageId}
            </span>
          );
        }
        return <span className="text-gray-400">—</span>;
      },
    },
  ];

  return (
    <div className="space-y-6 p-4 sm:p-6 lg:p-8">
      <div className="flex flex-wrap items-center justify-between gap-4">
        <div>
          <h1 className="text-xl font-semibold text-gray-900 dark:text-white">
            Milestone-Geräte
          </h1>
          {!isLoading && !error && (
            <p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
              {cameraCount} Kamera{cameraCount !== 1 ? "s" : ""},{" "}
              {micCount} Mikrofon{micCount !== 1 ? "e" : ""}
            </p>
          )}
        </div>
      </div>

      <div className="relative max-w-sm">
        <MagnifyingGlassIcon className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-gray-400" />
        <input
          type="search"
          placeholder="Suchen…"
          value={search}
          onChange={(e) => setSearch(e.target.value)}
          className="w-full rounded-lg border border-gray-300 bg-white py-2 pl-9 pr-3 text-sm text-gray-900 placeholder-gray-400 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
        />
      </div>

      {isLoading && (
        <div className="flex justify-center py-16">
          <LoadingSpinner size="lg" label="Geräte werden geladen…" center />
        </div>
      )}

      {!isLoading && error && (
        <div className="rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-700 dark:border-red-800 dark:bg-red-900/20 dark:text-red-400">
          {error}
        </div>
      )}

      {!isLoading && !error && filtered.length === 0 && (
        <EmptyState
          icon={VideoCameraIcon}
          title={search ? "Keine Treffer" : "Keine Geräte gefunden"}
          description={
            search
              ? "Versuche einen anderen Suchbegriff."
              : "Es wurden keine Kameras oder Mikrofone in Milestone gefunden."
          }
          className="py-16"
        />
      )}

      {!isLoading && !error && filtered.length > 0 && (
        <Tables
          rows={filtered}
          columns={columns}
          getRowId={(row) => row.id}
          variant="border"
        />
      )}
    </div>
  );
}
