import { useEffect, useMemo, useState } from "react";
import { DateInput } from "@mantine/dates";
import { Loader2, Plus, Trash2 } from "lucide-react";
import {
  ActionIcon,
  Modal,
  Button,
  TextInput,
  Textarea,
  MultiSelect,
  Select,
  Switch,
  Stack,
  Group,
  Text,
  Box,
  SimpleGrid,
  Divider,
} from "@mantine/core";

import {
  RULE_ENGINE_SELECT_NONE,
  type FormFieldDef,
} from "@/pages/ruleEngine/config/resources";
import PhoneField, { isValidPhone } from "@/components/PhoneField";
import type { RuleEngineRecord } from "@/types/rule-engine";
import { RULE_ENGINE_POSITION_END } from "./ruleEngineOrder.utils";

export interface RuleEngineFormDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  title: string;
  description: string;
  fields: FormFieldDef[];
  initialRecord?: RuleEngineRecord | null;
  isSubmitting: boolean;
  selectOptionsLoading?: boolean;
  positionOptions?: { label: string; value: string }[];
  positionLoading?: boolean;
  onSubmit: (values: Record<string, unknown>) => void;
}

type FormRow =
  | { kind: "pair"; fields: [FormFieldDef, FormFieldDef] }
  | { kind: "single"; field: FormFieldDef };

/** One editable distance tier of a tierList field (raw input strings). */
type TierRow = { minKm: string; maxKm: string; rateValue: string };

const emptyTier = (fromKm = ""): TierRow => ({
  minKm: fromKm,
  maxKm: "",
  rateValue: "",
});

/**
 * Validate a tier set before submit: every tier complete, ranges sane, no
 * overlaps, and only the last tier open-ended. Returns the error message, or
 * null when the set is valid.
 */
const validateTiers = (rows: TierRow[]): string | null => {
  if (!rows.length) return "Add at least one tier.";
  for (const row of rows) {
    if (row.minKm === "" || row.rateValue === "") {
      return "Every tier needs a From km and a Rate value.";
    }
    if (row.maxKm !== "" && Number(row.maxKm) <= Number(row.minKm)) {
      return "Each tier's To km must be greater than its From km.";
    }
  }
  const sorted = [...rows].sort((a, b) => Number(a.minKm) - Number(b.minKm));
  for (let i = 1; i < sorted.length; i += 1) {
    const prev = sorted[i - 1];
    if (prev.maxKm === "") return "Only the last tier can leave To km empty.";
    if (Number(sorted[i].minKm) < Number(prev.maxKm)) {
      return `Tiers overlap around ${sorted[i].minKm} km — each distance must fall in exactly one tier.`;
    }
  }
  return null;
};

const isShortField = (field: FormFieldDef) =>
  field.type === "text" ||
  field.type === "number" ||
  field.type === "select" ||
  field.type === "date";

const buildFormRows = (fields: FormFieldDef[]): FormRow[] => {
  const rows: FormRow[] = [];
  let index = 0;

  while (index < fields.length) {
    const field = fields[index];

    if (
      field.type === "textarea" ||
      field.type === "boolean" ||
      field.type === "tierList"
    ) {
      rows.push({ kind: "single", field });
      index += 1;
      continue;
    }

    const next = fields[index + 1];
    if (next && isShortField(next)) {
      rows.push({ kind: "pair", fields: [field, next] });
      index += 2;
      continue;
    }

    rows.push({ kind: "single", field });
    index += 1;
  }

  return rows;
};

const buildInitialValues = (
  fields: FormFieldDef[],
  record?: RuleEngineRecord | null,
): Record<string, unknown> => {
  const values: Record<string, unknown> = {};
  for (const field of fields) {
    const raw =
      field.getInitialValue && record
        ? field.getInitialValue(record)
        : record?.[field.name];
    if (field.type === "multiselect") {
      values[field.name] = Array.isArray(raw) ? raw.map(String) : [];
    } else if (field.type === "tierList") {
      values[field.name] = [emptyTier("0")];
    } else if (raw !== undefined && raw !== null) {
      if (field.type === "date" && typeof raw === "string") {
        values[field.name] = raw.slice(0, 10);
      } else if (Array.isArray(raw)) {
        values[field.name] = raw.join(", ");
      } else {
        values[field.name] = raw;
      }
    } else if (field.defaultValue !== undefined) {
      values[field.name] = field.defaultValue;
    } else if (field.type === "boolean") {
      values[field.name] = false;
    } else if (field.type === "number") {
      values[field.name] = "";
    } else {
      values[field.name] = "";
    }
  }
  return values;
};

const resolveSelectValue = (
  field: FormFieldDef,
  values: Record<string, unknown>,
): string | undefined => {
  const raw = values[field.name];
  const isEmpty = raw === "" || raw === null || raw === undefined;

  if (field.optional && isEmpty) {
    return RULE_ENGINE_SELECT_NONE;
  }

  if (isEmpty) {
    return undefined;
  }

  return String(raw);
};

const inputStyles = {
  label: {
    fontWeight: 600,
    marginBottom: 6,
    color: "var(--mantine-color-gray-8)",
  },
} as const;

const RuleEngineFormDialog = ({
  open,
  onOpenChange,
  title,
  fields,
  initialRecord,
  isSubmitting,
  selectOptionsLoading = false,
  positionOptions,
  positionLoading = false,
  onSubmit,
}: RuleEngineFormDialogProps) => {
  const [values, setValues] = useState<Record<string, unknown>>(() =>
    buildInitialValues(fields, initialRecord),
  );
  const [position, setPosition] = useState(RULE_ENGINE_POSITION_END);
  const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});

  useEffect(() => {
    if (open) {
      setValues(buildInitialValues(fields, initialRecord));
      setPosition(RULE_ENGINE_POSITION_END);
      setFieldErrors({});
    }
  }, [open, fields, initialRecord]);

  const visibleFields = useMemo(
    () =>
      fields.filter((field) => {
        if (
          field.hideWhen &&
          field.hideWhen.equals.includes(
            String(values[field.hideWhen.field] ?? ""),
          )
        ) {
          return false;
        }
        if (
          field.showWhen &&
          !field.showWhen.equals.includes(
            String(values[field.showWhen.field] ?? ""),
          )
        ) {
          return false;
        }
        if (field.showIf && !field.showIf(values)) return false;
        return true;
      }),
    [fields, values],
  );

  const formRows = useMemo(() => buildFormRows(visibleFields), [visibleFields]);

  const setField = (name: string, value: unknown) => {
    setFieldErrors((current) =>
      current[name] ? { ...current, [name]: "" } : current,
    );
    setValues((current) => {
      // Mantine fires onChange even when the same option is re-picked, and the
      // cascades below clear dependent answers (yards, unit, scope). Re-picking
      // an unchanged value must be a no-op, or an untouched direction silently
      // wipes the yard pair and the submit fails with "origin/destination
      // missing" data the admin did fill in.
      if (current[name] === value) return current;
      const next = { ...current, [name]: value };
      // Changing what a rate applies to (or its surcharge trigger) can invalidate
      // the previously-chosen unit — reset it so the admin re-picks from the new
      // allowed set instead of submitting a stale, rejected unit.
      if (
        (name === "appliesTo" || name === "trigger") &&
        "rateUnit" in current
      ) {
        next.rateUnit = "";
      }
      // The legal yards depend on what the rate is for and which way it runs, so
      // a leg picked under the old answer is no longer valid — clear it instead
      // of submitting a pair the API will reject.
      if (
        (name === "appliesTo" || name === "tradeDirection") &&
        "originYardId" in current
      ) {
        next.originYardId = "";
        next.destinationYardId = "";
      }
      // Intercity asks for a container type or a bulk cargo type, never both —
      // switching kind drops whichever the other kind had filled in.
      if (name === "intercityKind") {
        next.containerTypeId = "";
        next.cargoTypeId = "";
      }
      // Cargo kind (customs / cancellation) decides both the container-type scope
      // and the legal units (container → per box/wagon, bulk → per ton/wagon).
      if (name === "cargoKind") {
        next.containerTypeId = "";
        next.cargoTypeId = "";
        next.rateUnit = "";
      }
      // Full customs and Ethiopian-only customs are alternatives on a service
      // type — switching one on drops the other so the API never sees both.
      if (name === "includesCustoms" && value === true) {
        next.includesEthiopianCustomsOnly = false;
      }
      if (name === "includesEthiopianCustomsOnly" && value === true) {
        next.includesCustoms = false;
      }
      // Turning the shipping-line toggle on or off swaps the entire form, so
      // nothing answered under the other shape may survive into the payload.
      if (name === "isShippingLineRate") {
        next.shippingLineCompanyId = "";
        next.shippingLineRateKind = "";
        next.shippingLineCargoKind = "";
        next.appliesTo = "";
        next.trigger = "";
        next.containerTypeId = "";
        next.cargoTypeId = "";
        next.originYardId = "";
        next.destinationYardId = "";
        next.rateUnit = "";
      }
      // Base-vs-surcharge and container-vs-bulk each decide the scope field and
      // the legal units for a shipping-line rate, exactly as appliesTo and
      // cargoKind do on the customer form.
      if (name === "shippingLineRateKind" || name === "shippingLineCargoKind") {
        next.containerTypeId = "";
        next.cargoTypeId = "";
        next.rateUnit = "";
        if (name === "shippingLineRateKind") {
          next.shippingLineCargoKind = "";
          next.trigger = "";
          next.originYardId = "";
          next.destinationYardId = "";
        }
      }
      return next;
    });
  };

  const handleSubmit = (event: React.FormEvent) => {
    event.preventDefault();
    const payload: Record<string, unknown> = {};
    // Required selects that are empty block the submit and mark themselves,
    // rather than posting an incomplete payload for the API to reject.
    setFieldErrors({});
    let blocked = false;

    for (const field of visibleFields) {
      // Derived fields always submit their computed value — never stale state.
      const raw = field.computeValue
        ? (field.computeValue(values) ?? "")
        : values[field.name];
      if (field.type === "multiselect") {
        // Always the full replacement list — the API syncs the relation to it.
        payload[field.name] = Array.isArray(raw) ? raw : [];
      } else if (field.type === "tierList") {
        const rows = (Array.isArray(raw) ? raw : []) as TierRow[];
        const error = validateTiers(rows);
        if (error) {
          setFieldErrors((current) => ({ ...current, [field.name]: error }));
          blocked = true;
        } else {
          payload[field.name] = rows.map((row) => ({
            minKm: Number(row.minKm),
            maxKm: row.maxKm === "" ? null : Number(row.maxKm),
            rateValue: Number(row.rateValue),
          }));
        }
      } else if (field.type === "number") {
        if (raw === "" || raw === undefined) continue;
        payload[field.name] = Number(raw);
      } else if (field.type === "boolean") {
        payload[field.name] = Boolean(raw);
      } else if (
        field.type === "select" &&
        (raw === "" || raw === RULE_ENGINE_SELECT_NONE)
      ) {
        // A required select left empty must not silently submit nothing — the
        // API rejects the payload with a message that reads as if the admin
        // skipped a field they never saw cleared (e.g. yards reset by a trade
        // direction change). Surface it on the field instead.
        if (!field.required) continue;
        setFieldErrors((current) => ({
          ...current,
          [field.name]: `${field.label} is required.`,
        }));
        blocked = true;
      } else if (field.type === "phone" && raw !== "" && raw !== undefined) {
        // The country-picker input emits a PARTIAL E.164 while the user is
        // still typing ("+25377"), which is non-empty and would post straight
        // through to a 400 from the API's own validator. Reject it here, on the
        // field, instead of as a server error the admin has to decode.
        if (!isValidPhone(String(raw))) {
          setFieldErrors((current) => ({
            ...current,
            [field.name]: `${field.label} is not a complete phone number.`,
          }));
          blocked = true;
        } else {
          payload[field.name] = raw;
        }
      } else if (raw === "" || raw === undefined) {
        if (!field.required) continue;
        payload[field.name] = raw;
      } else {
        payload[field.name] = raw;
      }
    }

    if (
      fields.some((f) => f.name === "code" && typeof payload.code === "string")
    ) {
      payload.code = String(payload.code).toUpperCase();
    }

    if (blocked) return;

    if (
      !initialRecord &&
      positionOptions &&
      position !== RULE_ENGINE_POSITION_END
    ) {
      payload.insertAfterId = position;
    }

    onSubmit(payload);
  };

  const renderField = (field: FormFieldDef) => {
    if (field.type === "boolean") {
      return (
        <Group
          key={field.name}
          justify="space-between"
          align="center"
          wrap="nowrap"
          gap="md"
          px="md"
          style={{
            minHeight: 42,
            background: "var(--mantine-color-gray-0)",
            border: "1px solid var(--mantine-color-gray-3)",
            borderRadius: "var(--mantine-radius-md)",
          }}
        >
          <Stack gap={2}>
            <Text size="sm" fw={600}>
              {field.label}
            </Text>
            {field.description ? (
              <Text size="xs" c="dimmed">
                {field.description}
              </Text>
            ) : null}
          </Stack>
          <Switch
            checked={Boolean(values[field.name])}
            onChange={(e) => setField(field.name, e.currentTarget.checked)}
            // A toggle that re-targets what an existing record means (e.g. who
            // a rate is priced for) is create-only — flipping it on a saved row
            // would silently change every booking that prices off it.
            disabled={
              field.disabled ||
              (field.disabledOnEdit && !!initialRecord) ||
              field.disabledIf?.(values) === true
            }
            size="md"
            color="edr-green"
          />
        </Group>
      );
    }

    // A plain string, so Mantine renders the label and its required asterisk
    // itself. Passing an element here put a flex box inside the <label>,
    // which added a line of dead space above every input and bumped
    // Mantine's own asterisk onto a line of its own.
    const label = field.label;

    if (field.type === "tierList") {
      const rows = Array.isArray(values[field.name])
        ? (values[field.name] as TierRow[])
        : [];
      const setRows = (next: TierRow[]) => setField(field.name, next);
      const setRow = (index: number, key: keyof TierRow, value: string) => {
        if (value.trim().startsWith("-")) return;
        setRows(
          rows.map((row, i) => (i === index ? { ...row, [key]: value } : row)),
        );
      };
      return (
        <Box key={field.name}>
          <Text size="sm" fw={600} mb={2} c="var(--mantine-color-gray-8)">
            {label}
          </Text>
          {field.description ? (
            <Text size="xs" c="dimmed" mb={8}>
              {field.description}
            </Text>
          ) : null}
          <Stack gap="xs">
            {rows.map((row, index) => (
              <Group key={index} gap="xs" wrap="nowrap" align="flex-end">
                <TextInput
                  label={index === 0 ? "From km" : undefined}
                  type="number"
                  min={0}
                  step="any"
                  placeholder="0"
                  value={row.minKm}
                  onChange={(e) =>
                    setRow(index, "minKm", e.currentTarget.value)
                  }
                  size="md"
                  radius="md"
                  styles={inputStyles}
                  style={{ flex: 1 }}
                />
                <TextInput
                  label={index === 0 ? "To km" : undefined}
                  type="number"
                  min={0}
                  step="any"
                  placeholder="No limit"
                  value={row.maxKm}
                  onChange={(e) =>
                    setRow(index, "maxKm", e.currentTarget.value)
                  }
                  size="md"
                  radius="md"
                  styles={inputStyles}
                  style={{ flex: 1 }}
                />
                <TextInput
                  label={index === 0 ? "Rate value" : undefined}
                  type="number"
                  min={0}
                  step="any"
                  placeholder="Rate per km"
                  value={row.rateValue}
                  onChange={(e) =>
                    setRow(index, "rateValue", e.currentTarget.value)
                  }
                  size="md"
                  radius="md"
                  styles={inputStyles}
                  style={{ flex: 1 }}
                />
                <ActionIcon
                  variant="subtle"
                  color="red"
                  size="lg"
                  mb={2}
                  aria-label="Remove tier"
                  disabled={rows.length === 1}
                  onClick={() => setRows(rows.filter((_, i) => i !== index))}
                >
                  <Trash2 size={16} />
                </ActionIcon>
              </Group>
            ))}
            <Group justify="flex-start">
              <Button
                variant="light"
                size="xs"
                leftSection={<Plus size={14} />}
                // The next tier naturally starts where the previous one ends.
                onClick={() =>
                  setRows([
                    ...rows,
                    emptyTier(rows[rows.length - 1]?.maxKm ?? ""),
                  ])
                }
              >
                Add tier
              </Button>
            </Group>
            {fieldErrors[field.name] ? (
              <Text size="xs" c="red">
                {fieldErrors[field.name]}
              </Text>
            ) : null}
          </Stack>
        </Box>
      );
    }

    if (field.type === "multiselect") {
      const options = field.optionsFromValues
        ? field.optionsFromValues(values)
        : (field.options ?? []);
      const selected = Array.isArray(values[field.name])
        ? (values[field.name] as string[])
        : [];
      return (
        <MultiSelect
          key={field.name}
          label={label}
          withAsterisk={field.required}
          description={field.description}
          placeholder={
            selectOptionsLoading
              ? "Loading options..."
              : (field.placeholder ?? "Select one or more")
          }
          value={selected}
          onChange={(v) => setField(field.name, v)}
          disabled={selectOptionsLoading}
          data={options
            .filter(
              (opt) =>
                opt.value !== "" && opt.value !== RULE_ENGINE_SELECT_NONE,
            )
            .map((opt) => ({ label: opt.label, value: opt.value }))}
          searchable
          clearable
          size="md"
          radius="md"
          styles={inputStyles}
        />
      );
    }

    if (field.type === "select") {
      // Dynamic options (e.g. rate unit) resolve from the live form values so
      // the choices track the other fields the admin has picked.
      const options = field.optionsFromValues
        ? field.optionsFromValues(values)
        : (field.options ?? []);
      // A derived select shows (and submits) its computed value and is locked,
      // matching the text-input branch — used by fields the shape decides on the
      // admin's behalf, e.g. a shipping-line rate's import-only direction.
      const computedSelect = field.computeValue
        ? String(field.computeValue(values) ?? "")
        : undefined;
      return (
        <Select
          key={field.name}
          label={label}
          description={field.description}
          placeholder={
            selectOptionsLoading
              ? "Loading options..."
              : (field.placeholder ?? "Select an option")
          }
          value={
            computedSelect !== undefined
              ? computedSelect
              : resolveSelectValue(field, values)
          }
          onChange={(v) =>
            setField(field.name, v === RULE_ENGINE_SELECT_NONE ? "" : v)
          }
          disabled={
            selectOptionsLoading ||
            field.disabled ||
            (field.disabledOnEdit && !!initialRecord) ||
            computedSelect !== undefined
          }
          // Mantine's Select is not a native input, so `required` only marks it
          // visually — handleSubmit is what actually blocks an empty one.
          required={field.required}
          error={fieldErrors[field.name] || undefined}
          data={options
            .filter((opt) => opt.value !== "")
            .map((opt) => ({
              label: opt.label,
              value: opt.value,
            }))}
          searchable
          clearable
          size="md"
          radius="md"
          styles={inputStyles}
        />
      );
    }

    if (field.type === "textarea") {
      return (
        <Textarea
          key={field.name}
          label={label}
          value={String(values[field.name] ?? "")}
          onChange={(e) => setField(field.name, e.currentTarget.value)}
          placeholder={field.placeholder}
          required={field.required}
          minRows={4}
          autosize
          maxRows={8}
          size="md"
          radius="md"
          styles={inputStyles}
        />
      );
    }

    if (field.type === "date") {
      const raw = String(values[field.name] ?? "");
      return (
        <DateInput
          key={field.name}
          label={label}
          description={field.description}
          placeholder="Select date"
          // Mantine's DateValue accepts a `YYYY-MM-DD` string, which is exactly
          // what the API's date columns take — so the value passes straight
          // through with no Date round-trip, and none of the UTC-parsing shift
          // that `new Date("2026-01-01")` would introduce east of Greenwich.
          value={raw || null}
          onChange={(v) => setField(field.name, v ?? "")}
          disabled={field.disabled || (field.disabledOnEdit && !!initialRecord)}
          required={field.required}
          error={fieldErrors[field.name] || undefined}
          clearable
          size="md"
          radius="md"
          styles={inputStyles}
        />
      );
    }

    if (field.type === "phone") {
      // Country-picker input restricted to Ethiopia and Djibouti — the two the
      // SMS gateway reaches. Emits E.164, so the API never guesses a country
      // from a bare local number.
      return (
        <PhoneField
          key={field.name}
          label={label}
          description={field.description}
          value={String(values[field.name] ?? "")}
          onChange={(v) => setField(field.name, v ?? "")}
          disabled={field.disabled || (field.disabledOnEdit && !!initialRecord)}
          required={field.required}
          error={fieldErrors[field.name] || undefined}
          placeholder={field.placeholder}
        />
      );
    }

    const isNumber = field.type === "number";
    const computed = field.computeValue
      ? field.computeValue(values)
      : undefined;

    return (
      <TextInput
        key={field.name}
        label={label}
        description={field.description}
        type={isNumber ? "number" : "text"}
        // Every rule-engine number (sizes, capacities, counts, points, rates,
        // display order) is a non-negative magnitude — reject negatives outright
        // rather than letting a typed "-" reach the API.
        min={isNumber ? 0 : undefined}
        // Without an explicit step the browser assumes 1 and refuses to submit
        // anything fractional — which blocked decimal rates, tonnages and
        // distances. The API is the one that decides which of these are whole
        // numbers (@IsInt on points/sizes/order, @IsNumber on money, tons, km),
        // so let the field carry decimals and let a 400 catch the rest.
        step={isNumber ? "any" : undefined}
        disabled={
          field.disabled ||
          (field.disabledOnEdit && !!initialRecord) ||
          computed !== undefined
        }
        value={String(
          (computed !== undefined ? computed : values[field.name]) ?? "",
        )}
        onChange={(e) => {
          const next = e.currentTarget.value;
          if (isNumber && next.trim().startsWith("-")) return;
          setField(field.name, next);
        }}
        placeholder={field.placeholder}
        required={field.required}
        size="md"
        radius="md"
        styles={inputStyles}
        rightSection={
          field.suffix ? (
            <Text size="sm" c="dimmed" fw={600} pr={4}>
              {field.suffix}
            </Text>
          ) : undefined
        }
        rightSectionWidth={field.suffix ? 52 : undefined}
      />
    );
  };

  return (
    <Modal
      opened={open}
      onClose={() => onOpenChange(false)}
      title={
        <Text size="lg" fw={700} lh={1.2}>
          {title}
        </Text>
      }
      centered
      size={720}
      radius="lg"
      padding="xl"
      overlayProps={{ backgroundOpacity: 0.45, blur: 3 }}
      styles={{
        content: {
          maxWidth: "min(720px, 95vw)",
        },
        body: {
          paddingTop: 20,
        },
      }}
    >
      <form onSubmit={handleSubmit}>
        <Stack gap="lg">
          <Box
            style={{
              maxHeight: "calc(65vh - 120px)",
              overflowY: "auto",
              paddingRight: 4,
            }}
          >
            <Stack gap="md">
              {!initialRecord && positionOptions ? (
                <Select
                  label="Position"
                  description="New items are appended to the end by default."
                  value={position}
                  onChange={(value) =>
                    setPosition(value ?? RULE_ENGINE_POSITION_END)
                  }
                  data={[
                    {
                      label: "At end (default)",
                      value: RULE_ENGINE_POSITION_END,
                    },
                    ...positionOptions,
                  ]}
                  searchable
                  disabled={positionLoading}
                  size="md"
                  radius="md"
                  styles={inputStyles}
                />
              ) : null}
              {formRows.map((row) =>
                row.kind === "pair" ? (
                  <SimpleGrid
                    key={`${row.fields[0].name}-${row.fields[1].name}`}
                    cols={2}
                    spacing="md"
                  >
                    <Box style={{ minWidth: 0 }}>
                      {renderField(row.fields[0])}
                    </Box>
                    <Box style={{ minWidth: 0 }}>
                      {renderField(row.fields[1])}
                    </Box>
                  </SimpleGrid>
                ) : (
                  <Box key={row.field.name}>{renderField(row.field)}</Box>
                ),
              )}
            </Stack>
          </Box>

          <Divider />

          <Group justify="flex-end" gap="sm">
            <Button
              variant="default"
              onClick={() => onOpenChange(false)}
              disabled={isSubmitting}
              radius="md"
              size="md"
            >
              Cancel
            </Button>
            <Button
              type="submit"
              disabled={isSubmitting}
              leftSection={
                isSubmitting ? (
                  <Loader2
                    size={18}
                    style={{ animation: "spin 1s linear infinite" }}
                  />
                ) : undefined
              }
              radius="md"
              color="edr-green"
              variant="filled"
              fw={600}
              size="md"
            >
              {isSubmitting ? "Saving..." : "Save"}
            </Button>
          </Group>
        </Stack>
      </form>
    </Modal>
  );
};

export default RuleEngineFormDialog;
