"use client";

import { useEffect, useRef, useState } from "react";
import {
  DndContext,
  type DragEndEvent,
  KeyboardSensor,
  PointerSensor,
  closestCenter,
  useSensor,
  useSensors,
} from "@dnd-kit/core";
import {
  SortableContext,
  arrayMove,
  sortableKeyboardCoordinates,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { api } from "@/lib/trpc";

import { FormFieldCard } from "./form-field-card";
import { FormFieldConfig } from "./form-field-config";
import { FormFieldTypePicker } from "./form-field-type-picker";

type FormField = {
  id: string;
  label: string;
  type: string;
  required: boolean;
  placeholder?: string;
  helpText?: string;
  options?: { label: string; value: string }[];
  defaultValue?: unknown;
  mappedProperty: string | null;
  validation?: {
    min?: number;
    max?: number;
    pattern?: string;
    maxLength?: number;
  };
  conditionals?: {
    fieldId: string;
    operator: string;
    value: unknown;
    action: string;
  }[];
};

type Draft = {
  title: string;
  description: string | null;
  isPublished: boolean;
  fields: FormField[];
};

function normalizeFields(raw: unknown): FormField[] {
  if (!Array.isArray(raw)) return [];
  return raw.map((item, i) => {
    const o = item as Record<string, unknown>;
    return {
      id: typeof o.id === "string" ? o.id : `field_${i}`,
      label: typeof o.label === "string" ? o.label : "Untitled",
      type: typeof o.type === "string" ? o.type : "short_text",
      required: Boolean(o.required),
      placeholder:
        typeof o.placeholder === "string" ? o.placeholder : undefined,
      helpText: typeof o.helpText === "string" ? o.helpText : undefined,
      options: Array.isArray(o.options) ? (o.options as FormField["options"]) : undefined,
      defaultValue: o.defaultValue,
      mappedProperty:
        o.mappedProperty === null || typeof o.mappedProperty === "string"
          ? (o.mappedProperty as string | null)
          : null,
      validation:
        o.validation && typeof o.validation === "object"
          ? (o.validation as FormField["validation"])
          : undefined,
      conditionals: Array.isArray(o.conditionals)
        ? (o.conditionals as FormField["conditionals"])
        : undefined,
    };
  });
}

function createField(type: string): FormField {
  const id =
    typeof crypto !== "undefined" && crypto.randomUUID
      ? crypto.randomUUID()
      : `fld_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;

  const field: FormField = {
    id,
    label: "Untitled",
    type,
    required: false,
    mappedProperty: null,
  };

  if (type === "select" || type === "multi_select" || type === "radio") {
    field.options = [
      { label: "Option 1", value: "option_1" },
      { label: "Option 2", value: "option_2" },
    ];
  }

  return field;
}

export function FormBuilder({
  formId,
  workspaceHandle,
}: {
  formId: string;
  workspaceHandle: string;
}) {
  const utils = api.useUtils();
  const [draft, setDraft] = useState<Draft | null>(null);
  const [selectedFieldId, setSelectedFieldId] = useState<string | null>(null);
  const [pickerOpen, setPickerOpen] = useState(false);
  const hydratedRef = useRef(false);
  const skipSaveRef = useRef(false);

  const formQuery = api.forms.getById.useQuery(
    { workspace: workspaceHandle, id: formId },
    { enabled: Boolean(formId) && Boolean(workspaceHandle) },
  );

  const updateMutation = api.forms.update.useMutation({
    onSuccess: () => {
      void utils.forms.getById.invalidate({ workspace: workspaceHandle, id: formId });
    },
  });

  useEffect(() => {
    hydratedRef.current = false;
    setDraft(null);
    setSelectedFieldId(null);
  }, [formId, workspaceHandle]);

  useEffect(() => {
    if (
      !formQuery.isSuccess ||
      !formQuery.data ||
      formQuery.data.id !== formId
    ) {
      return;
    }
    if (hydratedRef.current) return;
    const row = formQuery.data;
    setDraft({
      title: row.title,
      description: row.description ?? null,
      isPublished: row.isPublished,
      fields: normalizeFields(row.fields),
    });
    hydratedRef.current = true;
    skipSaveRef.current = true;
  }, [formQuery.isSuccess, formQuery.data, formId]);

  useEffect(() => {
    if (!draft || !hydratedRef.current) return;
    if (skipSaveRef.current) {
      skipSaveRef.current = false;
      return;
    }

    const t = setTimeout(() => {
      updateMutation.mutate({
        workspace: workspaceHandle,
        id: formId,
        title: draft.title,
        description: draft.description,
        fields: draft.fields,
        isPublished: draft.isPublished,
      });
    }, 550);

    return () => clearTimeout(t);
  }, [draft, formId, workspaceHandle, updateMutation]);

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 6 } }),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    }),
  );

  const onDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over || active.id === over.id || !draft) return;

    const oldIndex = draft.fields.findIndex((f) => f.id === active.id);
    const newIndex = draft.fields.findIndex((f) => f.id === over.id);
    if (oldIndex < 0 || newIndex < 0) return;

    setDraft({
      ...draft,
      fields: arrayMove(draft.fields, oldIndex, newIndex),
    });
  };

  const updateField = (id: string, patch: Partial<FormField>) => {
    setDraft((d) => {
      if (!d) return d;
      return {
        ...d,
        fields: d.fields.map((f) => (f.id === id ? { ...f, ...patch } : f)),
      };
    });
  };

  const deleteField = (id: string) => {
    setDraft((d) => {
      if (!d) return d;
      return {
        ...d,
        fields: d.fields.filter((f) => f.id !== id),
      };
    });
    setSelectedFieldId((cur) => (cur === id ? null : cur));
  };

  const selectedField = draft?.fields.find((f) => f.id === selectedFieldId);

  if (formQuery.isLoading || draft === null) {
    return (
      <div className="rounded-lg border border-dashed border-border bg-muted/20 p-12 text-center text-sm text-muted-foreground">
        Loading form…
      </div>
    );
  }

  if (formQuery.isError) {
    return (
      <div className="rounded-lg border border-destructive/40 bg-destructive/5 p-6 text-sm text-destructive">
        Could not load this form.
      </div>
    );
  }

  return (
    <div className="flex flex-col gap-8 lg:flex-row lg:items-start">
      <div className="min-w-0 flex-1 space-y-6">
        <div className="space-y-3">
          <Input
            value={draft.title}
            onChange={(e) =>
              setDraft((d) => (d ? { ...d, title: e.target.value } : d))
            }
            className="text-2xl font-semibold tracking-tight"
            placeholder="Form title"
          />
          <textarea
            value={draft.description ?? ""}
            onChange={(e) =>
              setDraft((d) =>
                d
                  ? {
                      ...d,
                      description: e.target.value || null,
                    }
                  : d,
              )
            }
            placeholder="Description (optional)"
            rows={3}
            className="flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
          />
        </div>

        <label className="flex cursor-pointer items-center gap-3 rounded-lg border border-border bg-card px-4 py-3 text-sm font-medium shadow-sm">
          <input
            type="checkbox"
            checked={draft.isPublished}
            onChange={(e) =>
              setDraft((d) =>
                d ? { ...d, isPublished: e.target.checked } : d,
              )
            }
            className="size-4 rounded border-input accent-primary"
          />
          Published
          <span className="text-xs font-normal text-muted-foreground">
            When on, the form can accept responses (when wired).
          </span>
        </label>

        <div className="space-y-3">
          <div className="flex flex-wrap items-center justify-between gap-2">
            <h2 className="text-sm font-semibold text-foreground">Fields</h2>
            <Button
              type="button"
              size="sm"
              variant="outline"
              onClick={() => setPickerOpen((o) => !o)}
            >
              {pickerOpen ? "Close picker" : "Add field"}
            </Button>
          </div>

          {pickerOpen ? (
            <div className="rounded-lg border border-border bg-muted/20 p-3">
              <p className="mb-2 text-xs text-muted-foreground">
                Choose a field type
              </p>
              <FormFieldTypePicker
                onSelect={(type) => {
                  const next = createField(type);
                  setDraft((d) =>
                    d ? { ...d, fields: [...d.fields, next] } : d,
                  );
                  setSelectedFieldId(next.id);
                  setPickerOpen(false);
                }}
              />
            </div>
          ) : null}

          <DndContext
            sensors={sensors}
            collisionDetection={closestCenter}
            onDragEnd={onDragEnd}
          >
            <SortableContext
              items={draft.fields.map((f) => f.id)}
              strategy={verticalListSortingStrategy}
            >
              {draft.fields.length === 0 ? (
                <p className="rounded-lg border border-dashed border-border py-10 text-center text-sm text-muted-foreground">
                  No fields yet. Add a field to start building.
                </p>
              ) : (
                <ul className="flex flex-col gap-2">
                  {draft.fields.map((field) => (
                    <li key={field.id}>
                      <FormFieldCard
                        field={field}
                        isSelected={field.id === selectedFieldId}
                        onSelect={() => setSelectedFieldId(field.id)}
                        onChange={(patch) => updateField(field.id, patch)}
                        onDelete={() => deleteField(field.id)}
                      />
                    </li>
                  ))}
                </ul>
              )}
            </SortableContext>
          </DndContext>
        </div>

        {updateMutation.isError ? (
          <p className="text-xs text-destructive">
            Failed to save changes. Try again.
          </p>
        ) : null}
      </div>

      <aside className="w-full shrink-0 lg:sticky lg:top-6 lg:w-96">
        {selectedField ? (
          <FormFieldConfig
            key={selectedField.id}
            field={selectedField}
            allFields={draft.fields}
            workspaceHandle={workspaceHandle}
            onChange={(patch) => updateField(selectedField.id, patch)}
          />
        ) : (
          <div className="rounded-lg border border-dashed border-border bg-muted/10 p-6 text-center text-sm text-muted-foreground">
            Select a field to edit its settings, validation, mapping, and
            conditional rules.
          </div>
        )}
      </aside>
    </div>
  );
}
