﻿import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  Button,
  Checkbox,
  Combobox,
  Dialog,
  DialogActions,
  DialogBody,
  DialogContent,
  DialogSurface,
  DialogTitle,
  Field,
  Input,
  makeStyles,
  Option,
  shorthands,
  Table,
  TableBody,
  TableCell,
  TableHeader,
  TableHeaderCell,
  TableRow,
  Tooltip,
} from "@fluentui/react-components";
import { AddRegular, DeleteRegular, EditRegular, OpenRegular, LinkMultiple24Regular } from "@fluentui/react-icons";
import { useState } from "react";
import { Link } from "react-router-dom";
import { portalApi } from "../api/portalApi";
import { DataState } from "../components/DataState";
import { PageHeader } from "../components/PageHeader";
import type { Domain } from "../types/portal";

const useStyles = makeStyles({
  toolbar: {
    display: "flex",
    justifyContent: "flex-start",
    gap: "10px",
    marginBottom: "18px",
  },
  form: {
    display: "grid",
    gap: "14px",
  },
  actions: {
    display: "flex",
    gap: "4px",
    ...shorthands.padding("2px", "0"),
  },
});

type DialogMode = "add" | "edit" | null;

export function DomainsPage() {
  const styles = useStyles();
  const queryClient = useQueryClient();
  const [dialogMode, setDialogMode] = useState<DialogMode>(null);
  const [selectedDomain, setSelectedDomain] = useState<Domain | null>(null);
  const [name, setName] = useState("");
  const [fqdn, setFqdn] = useState("");
  const [netBIOS, setNetBIOS] = useState("");
  const [linkDomainId, setLinkDomainId] = useState("");
  const [environmentId, setEnvironmentId] = useState("");
  const [selectedIds, setSelectedIds] = useState<string[]>([]);
  const { data, error, isLoading } = useQuery({
    queryKey: ["domains"],
    queryFn: ({ signal }) => portalApi.getDomains(signal),
  });
  const { data: environments, error: environmentsError, isLoading: environmentsLoading } = useQuery({
    queryKey: ["environments"],
    queryFn: ({ signal }) => portalApi.getEnvironments(signal),
  });

  const closeDialog = () => {
    setDialogMode(null);
    setSelectedDomain(null);
    setName("");
    setFqdn("");
    setNetBIOS("");
  };

  const openAddDialog = () => {
    setSelectedDomain(null);
    setName("");
    setFqdn("");
    setNetBIOS("");
    setDialogMode("add");
  };

  const openEditDialog = (domain: Domain) => {
    setSelectedDomain(domain);
    setName(domain.name);
    setFqdn(domain.fqdn);
    setNetBIOS(domain.netBIOS);
    setDialogMode("edit");
  };

  const openLinkDialog = () => {
    setLinkDomainId(data?.[0]?.id ?? "");
    setEnvironmentId(environments?.[0]?.id ?? "");
  };

  const addDomain = useMutation({
    mutationFn: portalApi.addDomain,
    onSuccess: async () => {
      closeDialog();
      await queryClient.invalidateQueries({ queryKey: ["domains"] });
    },
  });

  const updateDomain = useMutation({
    mutationFn: ({ id, domain }: { id: string; domain: { name: string; fqdn: string; netBIOS: string } }) =>
      portalApi.updateDomain(id, domain),
    onSuccess: async () => {
      closeDialog();
      await queryClient.invalidateQueries({ queryKey: ["domains"] });
    },
  });

  const deleteDomain = useMutation({
    mutationFn: portalApi.deleteDomain,
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: ["domains"] });
    },
  });
  const deleteSelectedDomains = useMutation({
    mutationFn: async (ids: string[]) => {
      await Promise.all(ids.map((id) => portalApi.deleteDomain(id)));
    },
    onSuccess: async () => {
      setSelectedIds([]);
      await queryClient.invalidateQueries({ queryKey: ["domains"] });
    },
  });
  const linkDomainToEnvironment = useMutation({
    mutationFn: ({ domainId, environmentId: targetEnvironmentId }: { domainId: string; environmentId: string }) =>
      portalApi.linkDomainToEnvironment(domainId, targetEnvironmentId),
    onSuccess: async () => {
      setLinkDomainId("");
      setEnvironmentId("");
      await queryClient.invalidateQueries({ queryKey: ["domains"] });
      await queryClient.invalidateQueries({ queryKey: ["environments"] });
    },
  });

  const submitDomain = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const domain = { fqdn, name, netBIOS };

    if (dialogMode === "edit" && selectedDomain) {
      updateDomain.mutate({ id: selectedDomain.id, domain });
      return;
    }

    addDomain.mutate(domain);
  };

  const formError = addDomain.error?.message ?? updateDomain.error?.message;
  const isSaving = addDomain.isPending || updateDomain.isPending;
  const allSelected = Boolean(data?.length) && data!.every((domain) => selectedIds.includes(domain.id));
  const toggleSelected = (id: string, checked: boolean) => {
    setSelectedIds((current) => (checked ? [...new Set([...current, id])] : current.filter((entry) => entry !== id)));
  };

  return (
    <>
      <PageHeader title="Domains" description="Verfuegbare Active Directory Domaenen." />
      <div className={styles.toolbar}>
        <Button appearance="primary" icon={<AddRegular />} onClick={openAddDialog}>
          Domain hinzufuegen
        </Button>
        <Button appearance="secondary" icon={<LinkMultiple24Regular />} onClick={openLinkDialog}>
          Link to Environment
        </Button>
        <Button
          appearance="secondary"
          disabled={selectedIds.length === 0 || deleteSelectedDomains.isPending}
          icon={<DeleteRegular />}
          onClick={() => {
            if (window.confirm(`${selectedIds.length} Domains wirklich loeschen?`)) {
              deleteSelectedDomains.mutate(selectedIds);
            }
          }}
        >
          Auswahl loeschen
        </Button>
      </div>

      <Dialog open={dialogMode !== null} onOpenChange={(_, data) => !data.open && closeDialog()}>
        <DialogSurface>
          <form onSubmit={submitDomain}>
            <DialogBody>
              <DialogTitle>{dialogMode === "edit" ? "Domain aendern" : "Domain hinzufuegen"}</DialogTitle>
              <DialogContent className={styles.form}>
                <Field label="Name" required>
                  <Input value={name} onChange={(_, data) => setName(data.value)} />
                </Field>
                <Field label="FQDN" required>
                  <Input value={fqdn} onChange={(_, data) => setFqdn(data.value)} />
                </Field>
                <Field label="NetBIOS" required validationMessage={formError}>
                  <Input value={netBIOS} onChange={(_, data) => setNetBIOS(data.value)} />
                </Field>
              </DialogContent>
              <DialogActions>
                <Button appearance="secondary" onClick={closeDialog}>
                  Abbrechen
                </Button>
                <Button appearance="primary" disabled={!name || !fqdn || !netBIOS || isSaving} type="submit">
                  Speichern
                </Button>
              </DialogActions>
            </DialogBody>
          </form>
        </DialogSurface>
      </Dialog>
      <Dialog
        open={Boolean(linkDomainId || environmentId)}
        onOpenChange={(_, dialogData) => {
          if (!dialogData.open) {
            setLinkDomainId("");
            setEnvironmentId("");
          }
        }}
      >
        <DialogSurface>
          <DialogBody>
            <DialogTitle>Link to Environment</DialogTitle>
            <DialogContent className={styles.form}>
              <Field label="Domain" required>
                <Combobox
                  placeholder="Domain waehlen"
                  value={data?.find((domain) => domain.id === linkDomainId)?.name ?? ""}
                  onOptionSelect={(_, optionData) => setLinkDomainId(optionData.optionValue ?? "")}
                >
                  {(data ?? []).map((domain) => (
                    <Option key={domain.id} text={domain.name} value={domain.id}>
                      {domain.name}
                    </Option>
                  ))}
                </Combobox>
              </Field>
              <Field label="Environment" required validationMessage={linkDomainToEnvironment.error?.message}>
                <Combobox
                  disabled={environmentsLoading}
                  placeholder="Environment waehlen"
                  value={environments?.find((environment) => environment.id === environmentId)?.name ?? ""}
                  onOptionSelect={(_, data) => setEnvironmentId(data.optionValue ?? "")}
                >
                  {(environments ?? []).map((environment) => (
                    <Option key={environment.id} text={environment.name} value={environment.id}>
                      {environment.name}
                    </Option>
                  ))}
                </Combobox>
              </Field>
            </DialogContent>
            <DialogActions>
              <Button
                appearance="secondary"
                onClick={() => {
                  setLinkDomainId("");
                  setEnvironmentId("");
                }}
              >
                Abbrechen
              </Button>
              <Button
                appearance="primary"
                disabled={!linkDomainId || !environmentId || linkDomainToEnvironment.isPending}
                onClick={() => {
                  linkDomainToEnvironment.mutate({ domainId: linkDomainId, environmentId });
                }}
              >
                Link
              </Button>
            </DialogActions>
          </DialogBody>
        </DialogSurface>
      </Dialog>

      <DataState
        isLoading={isLoading || environmentsLoading}
        error={error ?? environmentsError ?? deleteDomain.error ?? deleteSelectedDomains.error ?? linkDomainToEnvironment.error}
      />
      {data && (
        <Table aria-label="Domains">
          <TableHeader>
            <TableRow>
              <TableHeaderCell>
                <Checkbox
                  checked={allSelected}
                  onChange={(_, checkboxData) => setSelectedIds(checkboxData.checked ? data.map((domain) => domain.id) : [])}
                />
              </TableHeaderCell>
              <TableHeaderCell>Name</TableHeaderCell>
              <TableHeaderCell>FQDN</TableHeaderCell>
              <TableHeaderCell>NetBIOS</TableHeaderCell>
              <TableHeaderCell>Id</TableHeaderCell>
              <TableHeaderCell>Aktionen</TableHeaderCell>
            </TableRow>
          </TableHeader>
          <TableBody>
            {data.map((domain) => (
              <TableRow key={domain.id}>
                <TableCell>
                  <Checkbox
                    checked={selectedIds.includes(domain.id)}
                    onChange={(_, checkboxData) => toggleSelected(domain.id, Boolean(checkboxData.checked))}
                  />
                </TableCell>
                <TableCell>{domain.name}</TableCell>
                <TableCell>{domain.fqdn}</TableCell>
                <TableCell>{domain.netBIOS}</TableCell>
                <TableCell>{domain.id}</TableCell>
                <TableCell>
                  <div className={styles.actions}>
                    <Tooltip content="Details" relationship="label">
                      <Link to={`/domains/${domain.id}`}>
                        <Button appearance="subtle" aria-label="Details" icon={<OpenRegular />} />
                      </Link>
                    </Tooltip>
                    <Tooltip content="Aendern" relationship="label">
                      <Button
                        appearance="subtle"
                        aria-label="Aendern"
                        icon={<EditRegular />}
                        onClick={() => openEditDialog(domain)}
                      />
                    </Tooltip>
                    <Tooltip content="Loeschen" relationship="label">
                      <Button
                        appearance="subtle"
                        aria-label="Loeschen"
                        disabled={deleteDomain.isPending}
                        icon={<DeleteRegular />}
                        onClick={() => {
                          if (window.confirm(`Domain "${domain.name}" wirklich loeschen?`)) {
                            deleteDomain.mutate(domain.id);
                          }
                        }}
                      />
                    </Tooltip>
                  </div>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      )}
    </>
  );
}

