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,
  Text,
  tokens,
  Tooltip,
} from "@fluentui/react-components";
import { AddRegular, DeleteRegular, OpenRegular } from "@fluentui/react-icons";
import { ChevronDownRegular, ChevronRightRegular } from "@fluentui/react-icons";
import { Fragment, useEffect, useMemo, 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 { DeploymentBatch } from "../types/portal";

const statusOrder = ["New", "Pending", "Running", "Failed", "Completed", "Unknown"];

const useStyles = makeStyles({
  pageActions: {
    display: "flex",
    gap: "10px",
    marginBottom: "16px",
  },
  groupRow: {
    cursor: "pointer",
  },
  groupHeader: {
    display: "flex",
    alignItems: "center",
    gap: "8px",
  },
  nestedLevel2Cell: {
    paddingLeft: "48px",
  },
  actions: {
    display: "flex",
    gap: "4px",
    ...shorthands.padding("2px", "0"),
  },
  muted: {
    color: tokens.colorNeutralForeground3,
  },
  idText: {
    color: tokens.colorNeutralForeground3,
    fontFamily: "Consolas, monospace",
    fontSize: "12px",
  },
  emptyState: {
    backgroundColor: tokens.colorNeutralBackground1,
    color: tokens.colorNeutralForeground3,
    ...shorthands.border("1px", "solid", tokens.colorNeutralStroke2),
    ...shorthands.borderRadius(tokens.borderRadiusMedium),
    ...shorthands.padding("24px"),
  },
  dialogIntro: {
    color: tokens.colorNeutralForeground3,
    marginBottom: "16px",
  },
  targetPicker: {
    display: "grid",
    gap: "10px",
  },
});

export function DeploymentGroupsPage() {
  const styles = useStyles();
  const queryClient = useQueryClient();
  const [serviceId, setServiceId] = useState("");
  const [templateId, setTemplateId] = useState("");
  const [templateVersionId, setTemplateVersionId] = useState("");
  const [deploymentRuleId, setDeploymentRuleId] = useState("");
  const [targetIds, setTargetIds] = useState<string[]>([]);
  const [targetSearch, setTargetSearch] = useState("");
  const [dialogOpen, setDialogOpen] = useState(false);
  const [deleteCandidate, setDeleteCandidate] = useState<DeploymentBatch | null>(null);
  const [selectedIds, setSelectedIds] = useState<string[]>([]);
  const [expandedStatusGroups, setExpandedStatusGroups] = useState<Record<string, boolean>>({});

  const { data, error, isLoading } = useQuery({
    queryKey: ["deployment-batches"],
    queryFn: ({ signal }) => portalApi.getDeploymentBatches(signal),
  });
  const { data: services } = useQuery({
    queryKey: ["services"],
    queryFn: ({ signal }) => portalApi.getServices(signal),
  });
  const { data: templates } = useQuery({
    queryKey: ["templates"],
    queryFn: ({ signal }) => portalApi.getTemplates(signal),
  });
  const { data: templateCategories } = useQuery({
    queryKey: ["template-categories"],
    queryFn: ({ signal }) => portalApi.getTemplateCategories(signal),
  });
  const { data: targets } = useQuery({
    queryKey: ["targets"],
    queryFn: ({ signal }) => portalApi.getTargets(signal),
  });
  const { data: templateVersions } = useQuery({
    queryKey: ["template-versions", templateId],
    queryFn: ({ signal }) => portalApi.getTemplateVersions(templateId, signal),
    enabled: Boolean(templateId),
  });
  const { data: deploymentRules } = useQuery({
    queryKey: ["deployment-rules"],
    queryFn: ({ signal }) => portalApi.getDeploymentRules(signal),
  });

  const addDeploymentBatch = useMutation({
    mutationFn: portalApi.addDeploymentBatch,
    onSuccess: async () => {
      setServiceId("");
      setTemplateId("");
      setTemplateVersionId("");
      setDeploymentRuleId("");
      setTargetIds([]);
      setTargetSearch("");
      setDialogOpen(false);
      await queryClient.invalidateQueries({ queryKey: ["deployment-batches"] });
      await queryClient.invalidateQueries({ queryKey: ["deployments"] });
    },
  });
  const deleteDeploymentBatch = useMutation({
    mutationFn: portalApi.deleteDeploymentBatch,
    onSuccess: async () => {
      setDeleteCandidate(null);
      await queryClient.invalidateQueries({ queryKey: ["deployment-batches"] });
      await queryClient.invalidateQueries({ queryKey: ["deployments"] });
    },
  });
  const deleteSelectedDeploymentBatches = useMutation({
    mutationFn: async (ids: string[]) => {
      await Promise.all(ids.map((id) => portalApi.deleteDeploymentBatch(id)));
    },
    onSuccess: async () => {
      setSelectedIds([]);
      await queryClient.invalidateQueries({ queryKey: ["deployment-batches"] });
      await queryClient.invalidateQueries({ queryKey: ["deployments"] });
    },
  });

  const selectedService = (services ?? []).find((service) => service.id === serviceId);
  const isOnPremService = selectedService ? !selectedService.isCloudService : false;
  const filteredTargets = useMemo(() => {
    const search = targetSearch.trim().toLowerCase();
    if (!search) {
      return targets ?? [];
    }

    return (targets ?? []).filter((target) => {
      const name = target.name?.toLowerCase() ?? "";
      const id = target.id?.toLowerCase() ?? "";
      return name.includes(search) || id.includes(search);
    });
  }, [targetSearch, targets]);
  const allVisibleSelected =
    filteredTargets.length > 0 &&
    filteredTargets.every((target) => targetIds.includes(target.id));

  const groupedBatches = useMemo(() => {
    const groups = (data ?? []).reduce<Record<string, DeploymentBatch[]>>((acc, deploymentBatch) => {
      const status = deploymentBatch.status || "Unknown";
      acc[status] = [...(acc[status] ?? []), deploymentBatch];
      return acc;
    }, {});

    return Object.entries(groups).sort(([left], [right]) => {
      const leftIndex = statusOrder.indexOf(left);
      const rightIndex = statusOrder.indexOf(right);
      return (leftIndex === -1 ? statusOrder.length : leftIndex) - (rightIndex === -1 ? statusOrder.length : rightIndex);
    });
  }, [data]);
  const allSelected = Boolean(data?.length) && data!.every((deploymentBatch) => selectedIds.includes(deploymentBatch.id));
  const toggleSelected = (id: string, checked: boolean) => {
    setSelectedIds((current) => (checked ? [...new Set([...current, id])] : current.filter((entry) => entry !== id)));
  };

  useEffect(() => {
    if (!templateVersions || templateVersions.length === 0 || templateVersionId) {
      return;
    }

    const publishedVersion = templateVersions.find((version) => version.isPublished);
    setTemplateVersionId((publishedVersion ?? templateVersions[0]).id);
  }, [templateVersionId, templateVersions]);

  const getServiceName = (deploymentBatch: DeploymentBatch) => {
    const template = (templates ?? []).find((entry) => entry.id === deploymentBatch.templateId);
    const category = (templateCategories ?? []).find((entry) => entry.id === template?.templateCategoryId);
    const service = (services ?? []).find((entry) => entry.id === category?.serviceId);
    return service?.name ?? "-";
  };

  const getPrimaryTemplateLabel = (deploymentBatch: DeploymentBatch) => {
    const fallbackTemplate = (templates ?? []).find((entry) => entry.id === deploymentBatch.templateId);
    const templateName = deploymentBatch.primaryTemplateName ?? fallbackTemplate?.name ?? "-";
    const templateVersion = deploymentBatch.primaryTemplateVersion ? ` ${deploymentBatch.primaryTemplateVersion}` : "";
    const additionalTemplates =
      deploymentBatch.templateSelectionCount > 1 ? ` +${deploymentBatch.templateSelectionCount - 1}` : "";
    return `${templateName}${templateVersion}${additionalTemplates}`;
  };

  const toggleStatusGroup = (status: string) => {
    setExpandedStatusGroups((current) => ({
      ...current,
      [status]: !current[status],
    }));
  };

  return (
    <>
      <PageHeader title="Deployments" description="Deployment Batches und Compositionen nach Status." />
      <div className={styles.pageActions}>
        <Button appearance="primary" icon={<AddRegular />} onClick={() => setDialogOpen(true)}>
          Neuer Deployment Batch
        </Button>
        <Button
          appearance="secondary"
          disabled={selectedIds.length === 0 || deleteSelectedDeploymentBatches.isPending}
          icon={<DeleteRegular />}
          onClick={() => {
            if (window.confirm(`${selectedIds.length} Deployment Batches wirklich loeschen?`)) {
              deleteSelectedDeploymentBatches.mutate(selectedIds);
            }
          }}
        >
          Auswahl loeschen
        </Button>
      </div>
      <DataState isLoading={isLoading} error={error ?? deleteSelectedDeploymentBatches.error} />
      {!isLoading && !error && groupedBatches.length === 0 && (
        <div className={styles.emptyState}>Keine Deployment Batches vorhanden.</div>
      )}
      {!isLoading && !error && groupedBatches.length > 0 && (
        <Table aria-label="Deployment batches">
          <TableHeader>
            <TableRow>
              <TableHeaderCell>
                <Checkbox
                  checked={allSelected}
                  onChange={(_, checkboxData) =>
                    setSelectedIds(checkboxData.checked ? (data ?? []).map((deploymentBatch) => deploymentBatch.id) : [])
                  }
                />
              </TableHeaderCell>
              <TableHeaderCell>
                <Text weight="semibold">Service</Text>
              </TableHeaderCell>
              <TableHeaderCell>
                <Text weight="semibold">Primary Template</Text>
              </TableHeaderCell>
              <TableHeaderCell>
                <Text weight="semibold">Templates</Text>
              </TableHeaderCell>
              <TableHeaderCell>
                <Text weight="semibold">Targets</Text>
              </TableHeaderCell>
              <TableHeaderCell>
                <Text weight="semibold">Rule</Text>
              </TableHeaderCell>
              <TableHeaderCell>
                <Text weight="semibold">Created</Text>
              </TableHeaderCell>
              <TableHeaderCell>
                <Text weight="semibold">Batch</Text>
              </TableHeaderCell>
              <TableHeaderCell>
                <Text weight="semibold">Actions</Text>
              </TableHeaderCell>
            </TableRow>
          </TableHeader>
          <TableBody>
            {groupedBatches.map(([status, deploymentBatches]) => (
              <Fragment key={`status-${status}`}>
                <TableRow className={styles.groupRow} onClick={() => toggleStatusGroup(status)}>
                  <TableCell colSpan={9}>
                    <div className={styles.groupHeader}>
                      {expandedStatusGroups[status] !== false ? <ChevronDownRegular /> : <ChevronRightRegular />}
                      <strong>{status}</strong>
                    </div>
                  </TableCell>
                </TableRow>
                {expandedStatusGroups[status] !== false &&
                  deploymentBatches.map((deploymentBatch) => (
                    <TableRow key={deploymentBatch.id}>
                      <TableCell>
                        <Checkbox
                          checked={selectedIds.includes(deploymentBatch.id)}
                          onChange={(_, checkboxData) => toggleSelected(deploymentBatch.id, Boolean(checkboxData.checked))}
                        />
                      </TableCell>
                      <TableCell className={styles.nestedLevel2Cell}>{getServiceName(deploymentBatch)}</TableCell>
                      <TableCell>{getPrimaryTemplateLabel(deploymentBatch)}</TableCell>
                      <TableCell>{deploymentBatch.templateSelectionCount ?? 0}</TableCell>
                      <TableCell>{deploymentBatch.targetAssignmentCount ?? 0}</TableCell>
                      <TableCell>
                        {(deploymentRules ?? []).find((entry) => entry.id === deploymentBatch.deploymentRuleId)?.name ?? "-"}
                      </TableCell>
                      <TableCell>{deploymentBatch.created ? new Date(deploymentBatch.created).toLocaleString() : "-"}</TableCell>
                      <TableCell>
                        <Tooltip content={deploymentBatch.id} relationship="label">
                          <span className={styles.idText}>{deploymentBatch.id.slice(0, 8)}</span>
                        </Tooltip>
                      </TableCell>
                      <TableCell>
                        <div className={styles.actions}>
                          <Tooltip content="Details" relationship="label">
                            <Link to={`/deployments/${deploymentBatch.id}`}>
                              <Button appearance="subtle" aria-label="Details" icon={<OpenRegular />} />
                            </Link>
                          </Tooltip>
                          <Tooltip content="Delete" relationship="label">
                            <Button
                              appearance="subtle"
                              aria-label="Delete"
                              icon={<DeleteRegular />}
                              onClick={() => setDeleteCandidate(deploymentBatch)}
                            />
                          </Tooltip>
                        </div>
                      </TableCell>
                    </TableRow>
                  ))}
              </Fragment>
            ))}
          </TableBody>
        </Table>
      )}

      <Dialog open={dialogOpen} onOpenChange={(_, data) => setDialogOpen(data.open)}>
        <DialogSurface>
          <DialogBody>
            <DialogTitle>Neuer Deployment Batch</DialogTitle>
            <DialogContent>
              <Text className={styles.dialogIntro}>
                Erstellt eine neue Deployment Composition mit einer initialen Template Selection.
              </Text>
              <Field label="Service" required>
                <Combobox
                  placeholder="Service waehlen"
                  value={services?.find((service) => service.id === serviceId)?.name ?? ""}
                  onOptionSelect={(_, data) => {
                    const nextServiceId = data.optionValue ?? "";
                    setServiceId(nextServiceId);
                    setTemplateId("");
                    setTemplateVersionId("");
                    setTargetIds([]);
                  }}
                >
                  {(services ?? []).map((service) => (
                    <Option key={service.id} text={service.name} value={service.id}>
                      {service.name}
                    </Option>
                  ))}
                </Combobox>
              </Field>
              <Field label="Initial Template" required>
                <Combobox
                  placeholder={serviceId ? "Template waehlen" : "Erst Service waehlen"}
                  disabled={!serviceId}
                  value={templates?.find((template) => template.id === templateId)?.name ?? ""}
                  onOptionSelect={(_, data) => {
                    setTemplateId(data.optionValue ?? "");
                    setTemplateVersionId("");
                  }}
                >
                  {(templates ?? [])
                    .filter((template) => {
                      const category = (templateCategories ?? []).find((entry) => entry.id === template.templateCategoryId);
                      return category?.serviceId === serviceId;
                    })
                    .map((template) => (
                      <Option key={template.id} text={template.name} value={template.id}>
                        {template.name}
                      </Option>
                    ))}
                </Combobox>
              </Field>
              <Field label="Version" required>
                <Combobox
                  placeholder={templateId ? "Version waehlen" : "Erst Template waehlen"}
                  disabled={!templateId}
                  value={templateVersions?.find((version) => version.id === templateVersionId)?.version ?? ""}
                  onOptionSelect={(_, data) => setTemplateVersionId(data.optionValue ?? "")}
                >
                  {(templateVersions ?? []).map((version) => (
                    <Option key={version.id} text={version.version} value={version.id}>
                      {version.version}
                      {version.isPublished ? " published" : ""}
                    </Option>
                  ))}
                </Combobox>
              </Field>
              <Field label="Deployment Rule">
                <Combobox
                  placeholder="Rule waehlen (optional)"
                  value={deploymentRules?.find((rule) => rule.id === deploymentRuleId)?.name ?? ""}
                  onOptionSelect={(_, data) => setDeploymentRuleId(data.optionValue ?? "")}
                >
                  {(deploymentRules ?? []).map((rule) => (
                    <Option key={rule.id} text={rule.name} value={rule.id}>
                      {rule.name}
                    </Option>
                  ))}
                </Combobox>
              </Field>
              {isOnPremService && (
                <Field label="Initial Targets" required>
                  <div className={styles.targetPicker}>
                    <Input
                      placeholder="Target suchen (Name oder Id)"
                      value={targetSearch}
                      onChange={(_, data) => setTargetSearch(data.value)}
                    />
                    <Table aria-label="Targets selection">
                      <TableHeader>
                        <TableRow>
                          <TableHeaderCell>
                            <Checkbox
                              checked={allVisibleSelected}
                              onChange={(_, data) => {
                                if (data.checked) {
                                  setTargetIds((prev) =>
                                    Array.from(new Set([...prev, ...filteredTargets.map((target) => target.id)])),
                                  );
                                } else {
                                  const visibleIds = new Set(filteredTargets.map((target) => target.id));
                                  setTargetIds((prev) => prev.filter((id) => !visibleIds.has(id)));
                                }
                              }}
                            />
                          </TableHeaderCell>
                          <TableHeaderCell>Name</TableHeaderCell>
                          <TableHeaderCell>Provider</TableHeaderCell>
                        </TableRow>
                      </TableHeader>
                      <TableBody>
                        {filteredTargets.map((target) => (
                          <TableRow key={target.id}>
                            <TableCell>
                              <Checkbox
                                checked={targetIds.includes(target.id)}
                                onChange={(_, data) => {
                                  if (data.checked) {
                                    setTargetIds((prev) => [...prev, target.id]);
                                  } else {
                                    setTargetIds((prev) => prev.filter((entry) => entry !== target.id));
                                  }
                                }}
                              />
                            </TableCell>
                            <TableCell>{target.name}</TableCell>
                            <TableCell>{target.providerType}</TableCell>
                          </TableRow>
                        ))}
                      </TableBody>
                    </Table>
                  </div>
                </Field>
              )}
            </DialogContent>
            <DialogActions>
              <Button appearance="secondary" onClick={() => setDialogOpen(false)}>
                Abbrechen
              </Button>
              <Button
                appearance="primary"
                disabled={!templateId || !templateVersionId || (isOnPremService && targetIds.length === 0) || addDeploymentBatch.isPending}
                onClick={() =>
                  addDeploymentBatch.mutate({
                    status: "New",
                    templateId,
                    templateVersionId,
                    deploymentRuleId: deploymentRuleId || undefined,
                    targetIds: isOnPremService ? targetIds : undefined,
                  })
                }
              >
                Batch anlegen
              </Button>
            </DialogActions>
          </DialogBody>
        </DialogSurface>
      </Dialog>

      <Dialog open={Boolean(deleteCandidate)} onOpenChange={(_, data) => !data.open && setDeleteCandidate(null)}>
        <DialogSurface>
          <DialogBody>
            <DialogTitle>Deployment Batch loeschen?</DialogTitle>
            <DialogContent>
              <Text>
                Der Batch {deleteCandidate?.id.slice(0, 8)} und seine Composition werden geloescht.
              </Text>
            </DialogContent>
            <DialogActions>
              <Button appearance="secondary" onClick={() => setDeleteCandidate(null)}>
                Abbrechen
              </Button>
              <Button
                appearance="primary"
                disabled={!deleteCandidate || deleteDeploymentBatch.isPending}
                icon={<DeleteRegular />}
                onClick={() => deleteCandidate && deleteDeploymentBatch.mutate(deleteCandidate.id)}
              >
                Loeschen
              </Button>
            </DialogActions>
          </DialogBody>
        </DialogSurface>
      </Dialog>
    </>
  );
}
