import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  Button,
  Combobox,
  Dialog,
  DialogActions,
  DialogBody,
  DialogContent,
  DialogSurface,
  DialogTitle,
  Field,
  Input,
  makeStyles,
  Option,
  Tab,
  TabList,
  shorthands,
  Table,
  TableBody,
  TableCell,
  TableHeader,
  TableHeaderCell,
  TableRow,
  Textarea,
  Tooltip,
} from "@fluentui/react-components";
import { AddRegular, DeleteRegular, EditRegular, OpenRegular } from "@fluentui/react-icons";
import { ChevronDownRegular, ChevronRightRegular } from "@fluentui/react-icons";
import { Fragment, useState } from "react";
import { portalApi } from "../api/portalApi";
import { DataState } from "../components/DataState";
import { PageHeader } from "../components/PageHeader";
import type { ServiceItem, Template, TemplateCategory } from "../types/portal";

const useStyles = makeStyles({
  toolbar: {
    display: "flex",
    justifyContent: "space-between",
    alignItems: "flex-end",
    gap: "12px",
    marginBottom: "18px",
  },
  toolbarActions: {
    display: "flex",
    gap: "8px",
    alignItems: "center",
  },
  filter: {
    minWidth: "280px",
  },
  form: {
    display: "grid",
    gap: "14px",
  },
  grid: {
    display: "grid",
    gap: "14px",
    gridTemplateColumns: "repeat(2, minmax(180px, 1fr))",
  },
  wide: {
    gridColumn: "1 / -1",
  },
  actions: {
    display: "flex",
    gap: "4px",
    ...shorthands.padding("2px", "0"),
  },
  value: {
    overflowWrap: "anywhere",
  },
  groupRow: {
    cursor: "pointer",
  },
  groupHeader: {
    display: "flex",
    alignItems: "center",
    gap: "8px",
  },
  nestedLevel1Cell: {
    paddingLeft: "28px",
  },
  nestedLevel2Cell: {
    paddingLeft: "48px",
  },
  categoryHeaderCell: {
    paddingTop: "10px",
    paddingBottom: "6px",
    paddingLeft: "28px",
  },
});

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

function getTemplateJsonData(template: Template) {
  return template.jsonData ?? template.jSONData ?? "";
}

type TemplateEditorTab = "parameters" | "variables" | "resources" | "raw";

function tryFormatJson(value: string) {
  try {
    if (!value.trim()) {
      return "";
    }
    return JSON.stringify(JSON.parse(value), null, 2);
  } catch {
    return value;
  }
}

function getCaseInsensitiveProperty(source: Record<string, unknown>, propertyName: string) {
  const key = Object.keys(source).find((entry) => entry.toLowerCase() === propertyName.toLowerCase());
  return key ? source[key] : undefined;
}

function normalizeEditorJsonParts(rawJson: string) {
  if (!rawJson.trim()) {
    return {
      raw: "",
      parameters: "{}",
      variables: "{}",
      resources: "[]",
    };
  }

  const parsed = JSON.parse(rawJson) as unknown;
  const root = parsed && typeof parsed === "object" ? (parsed as Record<string, unknown>) : {};

  const parameters = getCaseInsensitiveProperty(root, "parameters");
  const variables = getCaseInsensitiveProperty(root, "variables");
  const resources = getCaseInsensitiveProperty(root, "resources");

  return {
    raw: JSON.stringify(root, null, 2),
    parameters: JSON.stringify(
      parameters && typeof parameters === "object" && !Array.isArray(parameters) ? parameters : {},
      null,
      2,
    ),
    variables: JSON.stringify(
      variables && typeof variables === "object" && !Array.isArray(variables) ? variables : {},
      null,
      2,
    ),
    resources: JSON.stringify(Array.isArray(resources) ? resources : [], null, 2),
  };
}

export function TemplatesPage() {
  const styles = useStyles();
  const queryClient = useQueryClient();
  const [dialogMode, setDialogMode] = useState<DialogMode>(null);
  const [selectedTemplate, setSelectedTemplate] = useState<Template | null>(null);
  const [templateCategoryId, setTemplateCategoryId] = useState("");
  const [name, setName] = useState("");
  const [version, setVersion] = useState("");
  const [description, setDescription] = useState("");
  const [jsonData, setJsonData] = useState("");
  const [jsonParameters, setJsonParameters] = useState("{}");
  const [jsonVariables, setJsonVariables] = useState("{}");
  const [jsonResources, setJsonResources] = useState("[]");
  const [editorTab, setEditorTab] = useState<TemplateEditorTab>("parameters");
  const [serviceFilterId, setServiceFilterId] = useState("all");
  const [expandedServiceGroups, setExpandedServiceGroups] = useState<Record<string, boolean>>({});
  const [expandedCategoryGroups, setExpandedCategoryGroups] = useState<Record<string, boolean>>({});
  const { data, error, isLoading } = useQuery({
    queryKey: ["templates"],
    queryFn: ({ signal }) => portalApi.getTemplates(signal),
  });
  const {
    data: templateCategories,
    error: templateCategoriesError,
    isLoading: templateCategoriesLoading,
  } = useQuery({
    queryKey: ["template-categories"],
    queryFn: ({ signal }) => portalApi.getTemplateCategories(signal),
  });
  const { data: services, error: servicesError, isLoading: servicesLoading } = useQuery({
    queryKey: ["services"],
    queryFn: ({ signal }) => portalApi.getServices(signal),
  });

  const closeDialog = () => {
    setDialogMode(null);
    setSelectedTemplate(null);
    setTemplateCategoryId("");
    setName("");
    setVersion("");
    setDescription("");
    setJsonData("");
    setJsonParameters("{}");
    setJsonVariables("{}");
    setJsonResources("[]");
    setEditorTab("parameters");
  };

  const openAddDialog = () => {
    closeDialog();
    setDialogMode("add");
  };

  const openTemplateDialog = (mode: "edit" | "details", template: Template) => {
    setSelectedTemplate(template);
    setTemplateCategoryId(template.templateCategoryId ?? "");
    setName(template.name);
    setVersion(template.version ?? "");
    setDescription(template.description ?? "");
    const raw = getTemplateJsonData(template);
    try {
      const normalized = normalizeEditorJsonParts(raw);
      setJsonData(normalized.raw);
      setJsonParameters(normalized.parameters);
      setJsonVariables(normalized.variables);
      setJsonResources(normalized.resources);
    } catch {
      setJsonParameters("{}");
      setJsonVariables("{}");
      setJsonResources("[]");
      setJsonData(tryFormatJson(raw));
    }
    setDialogMode(mode);
  };

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

  const updateTemplate = useMutation({
    mutationFn: ({
      id,
      template,
    }: {
      id: string;
      template: {
        templateCategoryId: string;
        name: string;
        version: string;
        description: string;
        jsonData: string;
      };
    }) => portalApi.updateTemplate(id, template),
    onSuccess: async () => {
      closeDialog();
      await queryClient.invalidateQueries({ queryKey: ["templates"] });
    },
  });

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

  const submitTemplate = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    let composedJson = jsonData;
    try {
      const parsedRaw = jsonData.trim() ? JSON.parse(jsonData) : {};
      const parsedParameters = jsonParameters.trim() ? JSON.parse(jsonParameters) : {};
      const parsedVariables = jsonVariables.trim() ? JSON.parse(jsonVariables) : {};
      const parsedResources = jsonResources.trim() ? JSON.parse(jsonResources) : [];

      composedJson = JSON.stringify(
        {
          ...parsedRaw,
          parameters: parsedParameters,
          variables: parsedVariables,
          resources: parsedResources,
        },
        null,
        2,
      );
      setJsonData(composedJson);
    } catch {
      // keep current raw JSON and let backend validation respond
    }

    const template = { description, jsonData: composedJson, name, templateCategoryId, version };

    if (dialogMode === "edit" && selectedTemplate) {
      updateTemplate.mutate({ id: selectedTemplate.id, template });
      return;
    }

    addTemplate.mutate(template);
  };

  const formError = addTemplate.error?.message ?? updateTemplate.error?.message;
  const isSaving = addTemplate.isPending || updateTemplate.isPending;
  const isDetails = dialogMode === "details";
  const categoryNameById = new Map(
    (templateCategories ?? []).map((category: TemplateCategory) => [category.id, category.name]),
  );
  const categoryServiceIdById = new Map(
    (templateCategories ?? []).map((category: TemplateCategory) => [category.id, category.serviceId]),
  );
  const serviceNameById = new Map((services ?? []).map((service: ServiceItem) => [service.id, service.name]));
  const filteredTemplates =
    serviceFilterId === "all"
      ? (data ?? [])
      : (data ?? []).filter((template) => {
          const templateServiceId = template.templateCategoryId
            ? categoryServiceIdById.get(template.templateCategoryId)
            : undefined;
          return templateServiceId === serviceFilterId;
        });
  const groupedTemplates = (services ?? [])
    .map((service) => ({
      serviceId: service.id,
      serviceName: service.name,
      categories: (templateCategories ?? [])
        .filter((category) => category.serviceId === service.id)
        .map((category) => ({
          categoryId: category.id,
          categoryName: category.name,
          items: filteredTemplates
            .filter((template) => template.templateCategoryId === category.id)
            .sort((a, b) => a.name.localeCompare(b.name)),
        }))
        .filter((categoryGroup) => categoryGroup.items.length > 0)
        .sort((a, b) => a.categoryName.localeCompare(b.categoryName)),
    }))
    .filter((group) => group.categories.length > 0);

  const toggleServiceGroup = (serviceId: string) => {
    setExpandedServiceGroups((current) => ({
      ...current,
      [serviceId]: !current[serviceId],
    }));
  };

  const toggleCategoryGroup = (serviceId: string, categoryId: string) => {
    const key = `${serviceId}:${categoryId}`;
    setExpandedCategoryGroups((current) => ({
      ...current,
      [key]: !current[key],
    }));
  };

  return (
    <>
      <PageHeader title="Templates" description="Vorlagen fuer Portal-Bereitstellungen." />
      <div className={styles.toolbar}>
        <div className={styles.toolbarActions}>
          <Button appearance="primary" icon={<AddRegular />} onClick={openAddDialog}>
            Template hinzufuegen
          </Button>
        </div>
        <Field className={styles.filter} label="Service Filter">
          <Combobox
            placeholder="Alle Services"
            value={serviceFilterId === "all" ? "Alle Services" : serviceNameById.get(serviceFilterId) ?? ""}
            onOptionSelect={(_, selectData) => setServiceFilterId(selectData.optionValue ?? "all")}
          >
            <Option text="Alle Services" value="all">
              Alle Services
            </Option>
            {(services ?? []).map((service) => (
              <Option key={service.id} text={service.name} value={service.id}>
                {service.name}
              </Option>
            ))}
          </Combobox>
        </Field>
      </div>

      <Dialog open={dialogMode !== null} onOpenChange={(_, data) => !data.open && closeDialog()}>
        <DialogSurface>
          <form onSubmit={submitTemplate}>
            <DialogBody>
              <DialogTitle>
                {dialogMode === "edit"
                  ? "Template aendern"
                  : dialogMode === "details"
                    ? "Template Details"
                    : "Template hinzufuegen"}
              </DialogTitle>
              <DialogContent className={styles.form}>
                <div className={styles.grid}>
                  <Field label="Name" required>
                    <Input disabled={isDetails} value={name} onChange={(_, data) => setName(data.value)} />
                  </Field>
                  <Field label="Version" required>
                    <Input
                      disabled={isDetails}
                      value={version}
                      onChange={(_, data) => setVersion(data.value)}
                    />
                  </Field>
                  <Field className={styles.wide} label="Template Category" required validationMessage={formError}>
                    <Combobox
                      disabled={isDetails}
                      placeholder="Template Category waehlen"
                      value={categoryNameById.get(templateCategoryId) ?? ""}
                      onOptionSelect={(_, optionData) =>
                        setTemplateCategoryId(optionData.optionValue ?? "")
                      }
                    >
                      {(templateCategories ?? []).map((category) => (
                        <Option key={category.id} text={category.name} value={category.id}>
                          {category.name}
                        </Option>
                      ))}
                    </Combobox>
                  </Field>
                  <Field className={styles.wide} label="Description">
                    <Textarea
                      disabled={isDetails}
                      resize="vertical"
                      value={description}
                      onChange={(_, data) => setDescription(data.value)}
                    />
                  </Field>
                  <Field className={styles.wide} label="JSONData" required>
                    <TabList
                      selectedValue={editorTab}
                      onTabSelect={(_, tabData) => setEditorTab(tabData.value as TemplateEditorTab)}
                    >
                      <Tab value="parameters">Parameters</Tab>
                      <Tab value="variables">Variables</Tab>
                      <Tab value="resources">Resources</Tab>
                      <Tab value="raw">Raw JSON</Tab>
                    </TabList>
                    {editorTab === "parameters" && (
                      <Textarea
                        disabled={isDetails}
                        resize="vertical"
                        value={jsonParameters}
                        onChange={(_, data) => setJsonParameters(data.value)}
                      />
                    )}
                    {editorTab === "variables" && (
                      <Textarea
                        disabled={isDetails}
                        resize="vertical"
                        value={jsonVariables}
                        onChange={(_, data) => setJsonVariables(data.value)}
                      />
                    )}
                    {editorTab === "resources" && (
                      <Textarea
                        disabled={isDetails}
                        resize="vertical"
                        value={jsonResources}
                        onChange={(_, data) => setJsonResources(data.value)}
                      />
                    )}
                    {editorTab === "raw" && (
                      <Textarea
                        disabled={isDetails}
                        resize="vertical"
                        value={jsonData}
                        onChange={(_, data) => setJsonData(data.value)}
                      />
                    )}
                  </Field>
                  {selectedTemplate && (
                    <Field className={styles.wide} label="Id">
                      <div className={styles.value}>{selectedTemplate.id}</div>
                    </Field>
                  )}
                </div>
              </DialogContent>
              <DialogActions>
                <Button appearance="secondary" onClick={closeDialog}>
                  {isDetails ? "Schliessen" : "Abbrechen"}
                </Button>
                {!isDetails && (
                  <Button
                    appearance="primary"
                    disabled={!name || !templateCategoryId || !version || !jsonData || isSaving}
                    type="submit"
                  >
                    Speichern
                  </Button>
                )}
              </DialogActions>
            </DialogBody>
          </form>
        </DialogSurface>
      </Dialog>

      <DataState
        isLoading={isLoading || templateCategoriesLoading || servicesLoading}
        error={error ?? templateCategoriesError ?? servicesError ?? deleteTemplate.error}
      />
      {data && (
        <Table aria-label="Templates">
          <TableHeader>
            <TableRow>
              <TableHeaderCell>Name</TableHeaderCell>
              <TableHeaderCell>Version</TableHeaderCell>
              <TableHeaderCell>Template Category</TableHeaderCell>
              <TableHeaderCell>Id</TableHeaderCell>
              <TableHeaderCell>Aktionen</TableHeaderCell>
            </TableRow>
          </TableHeader>
          <TableBody>
            {groupedTemplates.map((group) => (
              <Fragment key={`group-${group.serviceId}`}>
                <TableRow className={styles.groupRow} onClick={() => toggleServiceGroup(group.serviceId)}>
                  <TableCell colSpan={5}>
                    <div className={styles.groupHeader}>
                      {expandedServiceGroups[group.serviceId] !== false ? <ChevronDownRegular /> : <ChevronRightRegular />}
                      <strong>{group.serviceName}</strong>
                    </div>
                  </TableCell>
                </TableRow>
                {expandedServiceGroups[group.serviceId] !== false && group.categories.map((categoryGroup) => (
                  <Fragment key={`group-${group.serviceId}-${categoryGroup.categoryId}`}>
                    <TableRow
                      className={styles.groupRow}
                      onClick={() => toggleCategoryGroup(group.serviceId, categoryGroup.categoryId)}
                    >
                      <TableCell className={styles.categoryHeaderCell} colSpan={5}>
                        <div className={styles.groupHeader}>
                          {expandedCategoryGroups[`${group.serviceId}:${categoryGroup.categoryId}`] !== false ? (
                            <ChevronDownRegular />
                          ) : (
                            <ChevronRightRegular />
                          )}
                          <strong>{categoryGroup.categoryName}</strong>
                        </div>
                      </TableCell>
                    </TableRow>
                    {expandedCategoryGroups[`${group.serviceId}:${categoryGroup.categoryId}`] !== false &&
                      categoryGroup.items.map((template) => (
                      <TableRow key={template.id}>
                        <TableCell className={styles.nestedLevel2Cell}>{template.name}</TableCell>
                        <TableCell>{template.version}</TableCell>
                        <TableCell>
                          {template.templateCategoryId ? categoryNameById.get(template.templateCategoryId) ?? template.templateCategoryId : ""}
                        </TableCell>
                        <TableCell>{template.id}</TableCell>
                        <TableCell>
                          <div className={styles.actions}>
                            <Tooltip content="Details" relationship="label">
                              <Button
                                appearance="subtle"
                                aria-label="Details"
                                icon={<OpenRegular />}
                                onClick={() => openTemplateDialog("details", template)}
                              />
                            </Tooltip>
                            <Tooltip content="Aendern" relationship="label">
                              <Button
                                appearance="subtle"
                                aria-label="Aendern"
                                icon={<EditRegular />}
                                onClick={() => openTemplateDialog("edit", template)}
                              />
                            </Tooltip>
                            <Tooltip content="Loeschen" relationship="label">
                              <Button
                                appearance="subtle"
                                aria-label="Loeschen"
                                disabled={deleteTemplate.isPending}
                                icon={<DeleteRegular />}
                                onClick={() => {
                                  if (window.confirm(`Template "${template.name}" wirklich loeschen?`)) {
                                    deleteTemplate.mutate(template.id);
                                  }
                                }}
                              />
                            </Tooltip>
                          </div>
                        </TableCell>
                      </TableRow>
                      ))}
                  </Fragment>
                ))}
              </Fragment>
            ))}
          </TableBody>
        </Table>
      )}
    </>
  );
}
