"use client";
import { jsxs, jsx } from 'react/jsx-runtime';
import { useId, useState, useCallback, useMemo } from 'react';
import { useSensors, useSensor, DndContext, closestCenter, DragOverlay, KeyboardSensor, TouchSensor, PointerSensor } from '../../../../../node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.mjs';
import { arrayMove, sortableKeyboardCoordinates } from '../../../../../node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/sortable/dist/sortable.esm.mjs';
import { cn } from '../../lib/utils.mjs';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../tabs.mjs';
import { Palette, PaletteDragOverlay } from './palette.mjs';
import { Canvas } from './canvas.mjs';
import { EditFieldDialog } from './edit-field-dialog.mjs';
import { NestedFieldEditorDialog } from './nested-field-editor-dialog.mjs';
import { FormPreview } from './form-preview.mjs';
import { FieldDragOverlay } from './sortable-field.mjs';
import { defaultComponents, getComponentByType } from './components/index.mjs';
export { arrayFieldDefinition, objectFieldDefinition } from './components/index.mjs';
import { jsonSchemaToFieldsAndSteps, fieldsToJSONSchema, createStep, generateFieldId } from './schema-utils.mjs';
export { baseMetaSchema, baseMetaSchemaWithPlaceholder } from './validation-schemas.mjs';

function FormBuilder({
  components = defaultComponents,
  value,
  onChange,
  className,
  fieldComponents,
  defaultValues
}) {
  const dndContextId = useId();
  const [fields, setFields] = useState(() => {
    if (!value) return [];
    const { fields: parsedFields } = jsonSchemaToFieldsAndSteps(value, components);
    return parsedFields;
  });
  const [steps, setSteps] = useState(() => {
    if (!value) return [];
    const { steps: parsedSteps } = jsonSchemaToFieldsAndSteps(value, components);
    return parsedSteps;
  });
  const [activeStepIndex, setActiveStepIndex] = useState(0);
  const [editDialogFieldId, setEditDialogFieldId] = useState(null);
  const [nestedEditorFieldId, setNestedEditorFieldId] = useState(null);
  const [activeId, setActiveId] = useState(null);
  const notifyChange = useCallback(
    (newFields, newSteps) => {
      if (onChange) {
        const schema = fieldsToJSONSchema(newFields, components, newSteps ?? steps);
        onChange(schema);
      }
    },
    [onChange, components, steps]
  );
  const currentSchema = useMemo(
    () => fieldsToJSONSchema(fields, components, steps),
    [fields, components, steps]
  );
  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        distance: 8
      }
    }),
    useSensor(TouchSensor, {
      activationConstraint: {
        // Use distance instead of delay for better compatibility with
        // automated testing tools and faster touch interactions
        distance: 8
      }
    }),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates
    })
  );
  const activeDragData = useMemo(() => {
    if (!activeId) return null;
    const idStr = String(activeId);
    if (idStr.startsWith("palette-")) {
      const componentType = idStr.replace("palette-", "");
      return {
        type: "palette",
        componentType,
        component: getComponentByType(componentType, components)
      };
    }
    const field = fields.find((f) => f.id === idStr);
    if (field) {
      return {
        type: "field",
        field,
        component: getComponentByType(field.type, components)
      };
    }
    return null;
  }, [activeId, fields, components]);
  const handleDragStart = (event) => {
    setActiveId(event.active.id);
  };
  const handleDragEnd = (event) => {
    const { active, over } = event;
    setActiveId(null);
    if (!over) return;
    const activeData = active.data.current;
    if (activeData?.type === "palette") {
      const { componentType } = activeData;
      const component = getComponentByType(componentType, components);
      if (component) {
        const newField = {
          id: generateFieldId(componentType),
          type: componentType,
          props: {
            label: component.defaultProps.label || component.label,
            ...component.defaultProps
          },
          // Assign to active step when in multi-step mode
          ...steps.length > 1 ? { stepGroup: activeStepIndex } : {}
        };
        let insertIndex = fields.length;
        const overId = String(over.id);
        if (overId === "drop-zone-start") {
          insertIndex = 0;
        } else if (overId.startsWith("drop-zone-")) {
          const fieldId = overId.replace("drop-zone-", "");
          const overIndex = fields.findIndex((f) => f.id === fieldId);
          if (overIndex !== -1) {
            insertIndex = overIndex + 1;
          }
        } else if (overId !== "canvas") {
          const overIndex = fields.findIndex((f) => f.id === overId);
          if (overIndex !== -1) {
            insertIndex = overIndex + 1;
          }
        }
        const newFields = [...fields];
        newFields.splice(insertIndex, 0, newField);
        setFields(newFields);
        notifyChange(newFields);
      }
      return;
    }
    if (activeData?.type === "field" && active.id !== over.id) {
      const oldIndex = fields.findIndex((f) => f.id === active.id);
      const newIndex = fields.findIndex((f) => f.id === over.id);
      if (oldIndex !== -1 && newIndex !== -1) {
        const newFields = arrayMove(fields, oldIndex, newIndex);
        setFields(newFields);
        notifyChange(newFields);
      }
    }
  };
  const handleUpdateField = useCallback(
    (id, props, newId, stepGroup) => {
      if (newId && newId !== id) {
        const idExists = fields.some((f) => f.id === newId && f.id !== id);
        if (idExists) {
          console.warn(`Cannot rename field "${id}" to "${newId}": a field with that ID already exists`);
          return;
        }
      }
      const newFields = fields.map((f) => {
        if (f.id !== id) return f;
        const updated = {
          ...f,
          id: newId || f.id,
          props: { ...f.props, ...props }
        };
        if (stepGroup !== void 0) {
          updated.stepGroup = stepGroup;
        }
        return updated;
      });
      setFields(newFields);
      notifyChange(newFields);
    },
    [fields, notifyChange]
  );
  const handleEditField = useCallback((id) => {
    setEditDialogFieldId(id);
  }, []);
  const handleDeleteField = useCallback(
    (id) => {
      const newFields = fields.filter((f) => f.id !== id);
      setFields(newFields);
      notifyChange(newFields);
    },
    [fields, notifyChange]
  );
  const handleConfigureNested = useCallback((id) => {
    setNestedEditorFieldId(id);
  }, []);
  const handleSaveNestedFields = useCallback(
    (fieldId, nestedFields) => {
      const newFields = fields.map((f) => {
        if (f.id !== fieldId) return f;
        if (f.type === "object") {
          return { ...f, children: nestedFields };
        } else if (f.type === "array") {
          return { ...f, itemTemplate: nestedFields };
        }
        return f;
      });
      setFields(newFields);
      notifyChange(newFields);
    },
    [fields, notifyChange]
  );
  const handleAddStep = useCallback(() => {
    const newStep = createStep(steps.length);
    const newSteps = [...steps, newStep];
    if (steps.length === 1) {
      const updatedFields = fields.map((f) => ({ ...f, stepGroup: 0 }));
      setFields(updatedFields);
      setSteps(newSteps);
      notifyChange(updatedFields, newSteps);
    } else if (steps.length === 0) {
      const firstStep = createStep(0);
      const secondStep = createStep(1);
      const bothSteps = [firstStep, secondStep];
      const updatedFields = fields.map((f) => ({ ...f, stepGroup: 0 }));
      setFields(updatedFields);
      setSteps(bothSteps);
      notifyChange(updatedFields, bothSteps);
    } else {
      setSteps(newSteps);
      notifyChange(fields, newSteps);
    }
  }, [steps, fields, notifyChange]);
  const handleDeleteStep = useCallback(
    (index) => {
      const fieldsWithoutDeleted = fields.filter((f) => f.stepGroup !== index);
      if (steps.length <= 2) {
        const updatedFields = fieldsWithoutDeleted.map((f) => {
          const { stepGroup: _, ...rest } = f;
          return rest;
        });
        setFields(updatedFields);
        setSteps([]);
        setActiveStepIndex(0);
        notifyChange(updatedFields, []);
      } else {
        const newSteps = steps.filter((_, i) => i !== index);
        const updatedFields = fieldsWithoutDeleted.map((f) => {
          if (f.stepGroup !== void 0 && f.stepGroup > index) {
            return { ...f, stepGroup: f.stepGroup - 1 };
          }
          return f;
        });
        setFields(updatedFields);
        setSteps(newSteps);
        if (activeStepIndex >= newSteps.length) {
          setActiveStepIndex(newSteps.length - 1);
        }
        notifyChange(updatedFields, newSteps);
      }
    },
    [steps, fields, activeStepIndex, notifyChange]
  );
  const handleRenameStep = useCallback(
    (index, newTitle) => {
      const newSteps = steps.map(
        (step, i) => i === index ? { ...step, title: newTitle } : step
      );
      setSteps(newSteps);
      notifyChange(fields, newSteps);
    },
    [steps, fields, notifyChange]
  );
  const editDialogField = fields.find((f) => f.id === editDialogFieldId) || null;
  const editDialogComponent = editDialogField ? getComponentByType(editDialogField.type, components) || null : null;
  const nestedEditorField = fields.find((f) => f.id === nestedEditorFieldId) || null;
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col lg:h-full", className), children: [
    /* @__PURE__ */ jsxs(
      DndContext,
      {
        id: dndContextId,
        sensors,
        collisionDetection: closestCenter,
        onDragStart: handleDragStart,
        onDragEnd: handleDragEnd,
        children: [
          /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col lg:flex-row lg:overflow-hidden", children: [
            /* @__PURE__ */ jsx("div", { className: "w-full lg:w-64 p-4 border-b lg:border-b-0 lg:border-r lg:overflow-auto shrink-0", children: /* @__PURE__ */ jsx(Palette, { components }) }),
            /* @__PURE__ */ jsx("div", { className: "flex-1 p-4 lg:overflow-auto min-h-[300px]", children: /* @__PURE__ */ jsx(
              Canvas,
              {
                fields,
                components,
                onEditField: handleEditField,
                onDeleteField: handleDeleteField,
                onConfigureNested: handleConfigureNested,
                isDraggingFromPalette: activeDragData?.type === "palette",
                steps,
                activeStepIndex,
                onActiveStepChange: setActiveStepIndex,
                onAddStep: handleAddStep,
                onDeleteStep: handleDeleteStep,
                onRenameStep: handleRenameStep
              }
            ) }),
            /* @__PURE__ */ jsx("div", { className: "w-full flex-1 lg:w-96 border-t lg:border-t-0 lg:border-l lg:overflow-auto min-h-[300px]", children: /* @__PURE__ */ jsxs(Tabs, { defaultValue: "preview", className: "h-full flex flex-col", children: [
              /* @__PURE__ */ jsx("div", { className: "p-4 border-b", children: /* @__PURE__ */ jsxs(TabsList, { className: "w-full", children: [
                /* @__PURE__ */ jsx(TabsTrigger, { value: "preview", className: "flex-1", children: "Preview" }),
                /* @__PURE__ */ jsx(TabsTrigger, { value: "schema", className: "flex-1", children: "JSON Schema" })
              ] }) }),
              /* @__PURE__ */ jsx(TabsContent, { value: "preview", className: "flex-1 m-0 lg:overflow-auto", children: /* @__PURE__ */ jsx(FormPreview, { schema: currentSchema, fieldComponents, defaultValues }) }),
              /* @__PURE__ */ jsx(TabsContent, { value: "schema", className: "flex-1 m-0 p-4 lg:overflow-auto", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-muted/50 p-4", children: /* @__PURE__ */ jsx("pre", { className: "text-sm overflow-auto whitespace-pre-wrap", children: JSON.stringify(currentSchema, null, 2) }) }) })
            ] }) })
          ] }),
          /* @__PURE__ */ jsxs(DragOverlay, { dropAnimation: null, children: [
            activeDragData?.type === "palette" && activeDragData.component && /* @__PURE__ */ jsx(PaletteDragOverlay, { component: activeDragData.component }),
            activeDragData?.type === "field" && activeDragData.field && /* @__PURE__ */ jsx(
              FieldDragOverlay,
              {
                field: activeDragData.field,
                component: activeDragData.component
              }
            )
          ] })
        ]
      }
    ),
    /* @__PURE__ */ jsx(
      EditFieldDialog,
      {
        open: editDialogFieldId !== null,
        onOpenChange: (open) => !open && setEditDialogFieldId(null),
        field: editDialogField,
        component: editDialogComponent,
        onUpdate: handleUpdateField,
        steps,
        allFieldIds: fields.map((f) => f.id)
      }
    ),
    /* @__PURE__ */ jsx(
      NestedFieldEditorDialog,
      {
        open: nestedEditorFieldId !== null,
        onOpenChange: (open) => !open && setNestedEditorFieldId(null),
        field: nestedEditorField,
        components,
        onSave: handleSaveNestedFields
      }
    )
  ] });
}

export { FormBuilder, FormBuilder as default, defaultComponents };
