﻿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,
  Textarea,
  Tooltip,
} from "@fluentui/react-components";
import { AddRegular, DeleteRegular, EditRegular, LinkDismissRegular, LinkRegular, OpenRegular } from "@fluentui/react-icons";
import { useState } from "react";
import { portalApi } from "../api/portalApi";
import { DataState } from "../components/DataState";
import { PageHeader } from "../components/PageHeader";
import type { Domain, Target } from "../types/portal";
import { Link } from "react-router-dom";

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

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

export function TargetsPage() {
  const styles = useStyles();
  const queryClient = useQueryClient();
  const [dialogMode, setDialogMode] = useState<DialogMode>(null);
  const [selectedTarget, setSelectedTarget] = useState<Target | null>(null);
  const [domainID, setDomainID] = useState<string | undefined>(undefined);
  const [linkTargetId, setLinkTargetId] = useState("");
  const [linkDomainId, setLinkDomainId] = useState("");
  const [unlinkTargetId, setUnlinkTargetId] = useState("");
  const [name, setName] = useState("");
  const [targetType, setTargetType] = useState("VirtualMachine");
  const [providerType, setProviderType] = useState("OnPrem");
  const [externalId, setExternalId] = useState("");
  const [metadataJson, setMetadataJson] = useState("");
  const [selectedIds, setSelectedIds] = useState<string[]>([]);

  const { data, error, isLoading } = useQuery({
    queryKey: ["targets"],
    queryFn: ({ signal }) => portalApi.getTargets(signal),
  });
  const { data: domains, error: domainsError, isLoading: domainsLoading } = useQuery({
    queryKey: ["domains"],
    queryFn: ({ signal }) => portalApi.getDomains(signal),
  });

  const closeDialog = () => {
    setDialogMode(null);
    setSelectedTarget(null);
    setDomainID(undefined);
    setName("");
    setTargetType("VirtualMachine");
    setProviderType("OnPrem");
    setExternalId("");
    setMetadataJson("");
  };

  const openAddDialog = () => {
    setSelectedTarget(null);
    setDomainID(undefined);
    setName("");
    setTargetType("VirtualMachine");
    setProviderType("OnPrem");
    setExternalId("");
    setMetadataJson("");
    setDialogMode("add");
  };

  const openTargetDialog = (mode: "edit", target: Target) => {
    setSelectedTarget(target);
    setDomainID(target.domainID);
    setName(target.name);
    setTargetType(target.targetType ?? "VirtualMachine");
    setProviderType(target.providerType ?? "OnPrem");
    setExternalId(target.externalId ?? "");
    setMetadataJson(target.metadataJson ?? "");
    setDialogMode(mode);
  };

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

  const updateTarget = useMutation({
    mutationFn: ({ id, target }: { id: string; target: { name: string; targetType: string; providerType: string; externalId?: string; metadataJson?: string } }) =>
      portalApi.updateTarget(id, target),
    onSuccess: async () => {
      closeDialog();
      await queryClient.invalidateQueries({ queryKey: ["targets"] });
    },
  });

  const deleteTarget = useMutation({
    mutationFn: portalApi.deleteTarget,
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: ["targets"] });
    },
  });
  const deleteSelectedTargets = useMutation({
    mutationFn: async (ids: string[]) => {
      await Promise.all(ids.map((id) => portalApi.deleteTarget(id)));
    },
    onSuccess: async () => {
      setSelectedIds([]);
      await queryClient.invalidateQueries({ queryKey: ["targets"] });
    },
  });

  const linkTargetToDomain = useMutation({
    mutationFn: ({ targetId, targetDomainId }: { targetId: string; targetDomainId: string }) =>
      portalApi.linkTargetToDomain(targetId, targetDomainId),
    onSuccess: async () => {
      setLinkTargetId("");
      setLinkDomainId("");
      await queryClient.invalidateQueries({ queryKey: ["targets"] });
    },
  });

  const unlinkTargetFromDomain = useMutation({
    mutationFn: (targetId: string) => portalApi.unlinkTargetFromDomain(targetId),
    onSuccess: async () => {
      setUnlinkTargetId("");
      await queryClient.invalidateQueries({ queryKey: ["targets"] });
    },
  });

  const submitTarget = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const target = { domainID, name, targetType, providerType, externalId, metadataJson };

    if (dialogMode === "edit" && selectedTarget) {
      updateTarget.mutate({ id: selectedTarget.id, target: { name, targetType, providerType, externalId, metadataJson } });
      return;
    }

    addTarget.mutate(target);
  };

  const formError =
    addTarget.error?.message ??
    updateTarget.error?.message ??
    linkTargetToDomain.error?.message ??
    unlinkTargetFromDomain.error?.message;
  const isSaving = addTarget.isPending || updateTarget.isPending;
  const domainNameById = new Map((domains ?? []).map((domain: Domain) => [domain.id, domain.name]));
  const linkedTargets = (data ?? []).filter((target) => Boolean(target.domainID));
  const unlinkedTargets = (data ?? []).filter((target) => !target.domainID);
  const allSelected = Boolean(data?.length) && data!.every((target) => selectedIds.includes(target.id));
  const toggleSelected = (id: string, checked: boolean) => {
    setSelectedIds((current) => (checked ? [...new Set([...current, id])] : current.filter((entry) => entry !== id)));
  };

  return (
    <>
      <PageHeader title="Targets" description="Generische Ziele fuer On-Prem-, Hybrid- und Cloud-Deployments verwalten." />
      <div className={styles.toolbar}>
        <Button appearance="primary" icon={<AddRegular />} onClick={openAddDialog}>
          Target hinzufuegen
        </Button>
        <Button
          appearance="secondary"
          icon={<LinkRegular />}
          onClick={() => {
            setLinkTargetId(unlinkedTargets[0]?.id ?? "");
            setLinkDomainId(domains?.[0]?.id ?? "");
          }}
          disabled={!unlinkedTargets.length || !domains?.length}
          style={{ marginLeft: "10px" }}
        >
          Link to Domain
        </Button>
        <Button
          appearance="secondary"
          icon={<LinkDismissRegular />}
          onClick={() => {
            setUnlinkTargetId(linkedTargets[0]?.id ?? "");
          }}
          disabled={!linkedTargets.length}
          style={{ marginLeft: "10px" }}
        >
          Unlink Domain
        </Button>
        <Button
          appearance="secondary"
          disabled={selectedIds.length === 0 || deleteSelectedTargets.isPending}
          icon={<DeleteRegular />}
          onClick={() => {
            if (window.confirm(`${selectedIds.length} Targets wirklich loeschen?`)) {
              deleteSelectedTargets.mutate(selectedIds);
            }
          }}
          style={{ marginLeft: "10px" }}
        >
          Auswahl loeschen
        </Button>
      </div>

      <Dialog open={dialogMode !== null} onOpenChange={(_, dialogData) => !dialogData.open && closeDialog()}>
        <DialogSurface>
          <form onSubmit={submitTarget}>
            <DialogBody>
              <DialogTitle>
                {dialogMode === "edit"
                  ? "Target aendern"
                  : "Target hinzufuegen"}
              </DialogTitle>
              <DialogContent className={styles.form}>
                <Field label="Domain (optional)" validationMessage={formError}>
                  <Combobox
                    disabled={domainsLoading}
                    placeholder="Domain waehlen"
                    value={domainID ? (domainNameById.get(domainID) ?? "") : ""}
                    onOptionSelect={(_, optionData) => setDomainID(optionData.optionValue || undefined)}
                  >
                    {(domains ?? []).map((domain) => (
                      <Option key={domain.id} text={domain.name} value={domain.id}>
                        {domain.name}
                      </Option>
                    ))}
                  </Combobox>
                </Field>
                <Field label="Name" required>
                  <Input value={name} onChange={(_, inputData) => setName(inputData.value)} />
                </Field>
                <Field label="Target Type" required>
                  <Combobox
                    value={targetType}
                    onOptionSelect={(_, optionData) => setTargetType(optionData.optionValue ?? "VirtualMachine")}
                  >
                    {["VirtualMachine", "Tenant", "Subscription", "ResourceGroup", "User", "Group", "Site", "PolicyScope"].map((type) => (
                      <Option key={type} text={type} value={type}>
                        {type}
                      </Option>
                    ))}
                  </Combobox>
                </Field>
                <Field label="Provider Type" required>
                  <Combobox
                    value={providerType}
                    onOptionSelect={(_, optionData) => setProviderType(optionData.optionValue ?? "OnPrem")}
                  >
                    {["OnPrem", "Azure", "Microsoft365", "ExchangeOnline", "Teams"].map((provider) => (
                      <Option key={provider} text={provider} value={provider}>
                        {provider}
                      </Option>
                    ))}
                  </Combobox>
                </Field>
                <Field label="External Id">
                  <Input
                    value={externalId}
                    onChange={(_, inputData) => setExternalId(inputData.value)}
                  />
                </Field>
                <Field label="Metadata JSON">
                  <Textarea
                    resize="vertical"
                    value={metadataJson}
                    onChange={(_, inputData) => setMetadataJson(inputData.value)}
                  />
                </Field>
                {selectedTarget && (
                  <Field label="Id">
                    <div className={styles.value}>{selectedTarget.id}</div>
                  </Field>
                )}
              </DialogContent>
              <DialogActions>
                <Button appearance="secondary" onClick={closeDialog}>
                  Abbrechen
                </Button>
                <Button appearance="primary" disabled={!name || isSaving} type="submit">
                  Speichern
                </Button>
              </DialogActions>
            </DialogBody>
          </form>
        </DialogSurface>
      </Dialog>

      <Dialog open={Boolean(linkTargetId)} onOpenChange={(_, dialogData) => !dialogData.open && setLinkTargetId("")}>
        <DialogSurface>
          <DialogBody>
            <DialogTitle>Link Target to Domain</DialogTitle>
            <DialogContent className={styles.form}>
              <Field label="Target" required>
                <Combobox
                  placeholder="Target waehlen"
                  value={(data ?? []).find((target) => target.id === linkTargetId)?.name ?? ""}
                  onOptionSelect={(_, optionData) => setLinkTargetId(optionData.optionValue ?? "")}
                >
                  {unlinkedTargets.map((target) => (
                    <Option key={target.id} text={target.name} value={target.id}>
                      {target.name}
                    </Option>
                  ))}
                </Combobox>
              </Field>
              <Field label="Domain" required>
                <Combobox
                  placeholder="Domain waehlen"
                  value={domains?.find((domain) => domain.id === linkDomainId)?.name ?? ""}
                  onOptionSelect={(_, optionData) => setLinkDomainId(optionData.optionValue ?? "")}
                >
                  {(domains ?? []).map((domain) => (
                    <Option key={domain.id} text={domain.name} value={domain.id}>
                      {domain.name}
                    </Option>
                  ))}
                </Combobox>
              </Field>
            </DialogContent>
            <DialogActions>
              <Button appearance="secondary" onClick={() => setLinkTargetId("")}>
                Abbrechen
              </Button>
              <Button
                appearance="primary"
                disabled={!linkTargetId || !linkDomainId || linkTargetToDomain.isPending}
                onClick={() => linkTargetToDomain.mutate({ targetId: linkTargetId, targetDomainId: linkDomainId })}
              >
                Link
              </Button>
            </DialogActions>
          </DialogBody>
        </DialogSurface>
      </Dialog>

      <Dialog open={Boolean(unlinkTargetId)} onOpenChange={(_, dialogData) => !dialogData.open && setUnlinkTargetId("")}>
        <DialogSurface>
          <DialogBody>
            <DialogTitle>Unlink Target from Domain</DialogTitle>
            <DialogContent className={styles.form}>
              <Field label="Target" required>
                <Combobox
                  placeholder="Target waehlen"
                  value={(data ?? []).find((target) => target.id === unlinkTargetId)?.name ?? ""}
                  onOptionSelect={(_, optionData) => setUnlinkTargetId(optionData.optionValue ?? "")}
                >
                  {linkedTargets.map((target) => (
                    <Option key={target.id} text={target.name} value={target.id}>
                      {target.name}
                    </Option>
                  ))}
                </Combobox>
              </Field>
            </DialogContent>
            <DialogActions>
              <Button appearance="secondary" onClick={() => setUnlinkTargetId("")}>
                Abbrechen
              </Button>
              <Button
                appearance="primary"
                disabled={!unlinkTargetId || unlinkTargetFromDomain.isPending}
                onClick={() => unlinkTargetFromDomain.mutate(unlinkTargetId)}
              >
                Unlink
              </Button>
            </DialogActions>
          </DialogBody>
        </DialogSurface>
      </Dialog>

      <DataState
        isLoading={isLoading || domainsLoading}
        error={error ?? domainsError ?? deleteTarget.error ?? deleteSelectedTargets.error ?? linkTargetToDomain.error ?? unlinkTargetFromDomain.error}
      />
      {data && (
        <Table aria-label="Targets">
          <TableHeader>
            <TableRow>
              <TableHeaderCell>
                <Checkbox
                  checked={allSelected}
                  onChange={(_, checkboxData) => setSelectedIds(checkboxData.checked ? data.map((target) => target.id) : [])}
                />
              </TableHeaderCell>
              <TableHeaderCell>Name</TableHeaderCell>
              <TableHeaderCell>Type</TableHeaderCell>
              <TableHeaderCell>Provider</TableHeaderCell>
              <TableHeaderCell>Domain</TableHeaderCell>
              <TableHeaderCell>External Id</TableHeaderCell>
              <TableHeaderCell>Id</TableHeaderCell>
              <TableHeaderCell>Aktionen</TableHeaderCell>
            </TableRow>
          </TableHeader>
          <TableBody>
            {data.map((target) => (
              <TableRow key={target.id}>
                <TableCell>
                  <Checkbox
                    checked={selectedIds.includes(target.id)}
                    onChange={(_, checkboxData) => toggleSelected(target.id, Boolean(checkboxData.checked))}
                  />
                </TableCell>
                <TableCell>{target.name}</TableCell>
                <TableCell>{target.targetType}</TableCell>
                <TableCell>{target.providerType}</TableCell>
                <TableCell>{target.domainID ? (domainNameById.get(target.domainID) ?? target.domainID) : "-"}</TableCell>
                <TableCell>{target.externalId}</TableCell>
                <TableCell>{target.id}</TableCell>
                <TableCell>
                  <div className={styles.actions}>
                    <Tooltip content="Details" relationship="label">
                      <Link to={`/targets/${target.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={() => openTargetDialog("edit", target)}
                      />
                    </Tooltip>
                    <Tooltip content="Loeschen" relationship="label">
                      <Button
                        appearance="subtle"
                        aria-label="Loeschen"
                        disabled={deleteTarget.isPending}
                        icon={<DeleteRegular />}
                        onClick={() => {
                          if (window.confirm(`Target "${target.name}" wirklich loeschen?`)) {
                            deleteTarget.mutate(target.id);
                          }
                        }}
                      />
                    </Tooltip>
                  </div>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      )}
    </>
  );
}

