"use client";

import { Button, inputClass } from "@/components/ui";
import { FIELD_KINDS, FIELD_KIND_LABEL, type FieldKind } from "@/lib/modules/schema";
import type { FieldDef } from "@/lib/blocks/defs";

/** Editable (string-typed) copy of a field definition. */
export interface EField { kind: FieldKind; key: string; label: string; help: string; max: string; options: string; min: string; maxN: string; itemLabel: string; listMax: string; fields: EField[]; keyTouched: boolean }

export const blankField = (kind: FieldKind = "text"): EField => ({ kind, key: "", label: "", help: "", max: "", options: "", min: "0", maxN: "100", itemLabel: "Item", listMax: "10", fields: [], keyTouched: false });

const slug = (s: string) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
export const camel = (label: string) => {
  const words = label.replace(/[^A-Za-z0-9]+/g, " ").trim().split(" ").filter(Boolean);
  const k = words.map((w, i) => (i === 0 ? w.toLowerCase() : w[0]!.toUpperCase() + w.slice(1).toLowerCase())).join("");
  return (/^[a-z]/.test(k) ? k : `f${k}`).slice(0, 30);
};

export function fromDef(d: FieldDef): EField {
  const e = blankField(d.kind as FieldKind);
  e.key = d.key; e.label = d.label; e.keyTouched = true;
  if ("help" in d && d.help) e.help = d.help;
  if ((d.kind === "text" || d.kind === "textarea" || d.kind === "link") && d.max) e.max = String(d.max);
  if (d.kind === "select") e.options = d.options.map((o) => `${o.value}|${o.label}`).join("\n");
  if (d.kind === "number") { e.min = String(d.min); e.maxN = String(d.max); }
  if (d.kind === "list") { e.itemLabel = d.itemLabel; e.listMax = String(d.max); e.fields = d.fields.map(fromDef); }
  return e;
}

const num = (v: string, fallback: number) => (v.trim() !== "" && Number.isFinite(Number(v)) ? Math.trunc(Number(v)) : fallback);

export function toDef(e: EField): Record<string, unknown> {
  const base = { kind: e.kind, key: e.key.trim(), label: e.label.trim() };
  switch (e.kind) {
    case "text": case "textarea": case "link": return { ...base, ...(e.help.trim() ? { help: e.help.trim() } : {}), ...(e.max.trim() ? { max: num(e.max, 200) } : {}) };
    case "media": return { ...base, ...(e.help.trim() ? { help: e.help.trim() } : {}) };
    case "select": return { ...base, options: e.options.split("\n").map((l) => l.trim()).filter(Boolean).map((l) => { const [a, ...r] = l.split("|"); return r.length ? { value: a!.trim(), label: r.join("|").trim() } : { value: slug(l), label: l }; }) };
    case "number": return { ...base, min: num(e.min, 0), max: num(e.maxN, 100) };
    case "list": return { ...base, itemLabel: e.itemLabel.trim(), max: num(e.listMax, 10), fields: e.fields.map(toDef) };
  }
}

const sel = `${inputClass}`;

export function FieldRow({ f, idp, nested, index, count, onChange, onRemove, onMove }: { f: EField; idp: string; nested?: boolean; index: number; count: number; onChange: (n: EField) => void; onRemove: () => void; onMove: (dir: -1 | 1) => void }) {
  const set = (p: Partial<EField>) => onChange({ ...f, ...p });
  const kinds = nested ? FIELD_KINDS.filter((k) => k !== "list") : FIELD_KINDS;
  return (
    <li className="rounded-md border border-border bg-card p-3">
      <div className="grid gap-2 sm:grid-cols-[10rem_1fr_1fr_auto]">
        <div><label htmlFor={`${idp}-kind`} className="mb-1 block text-xs font-medium">Type</label>
          <select id={`${idp}-kind`} className={sel} value={f.kind} onChange={(e) => set({ kind: e.target.value as FieldKind })}>{kinds.map((k) => <option key={k} value={k}>{FIELD_KIND_LABEL[k]}</option>)}</select></div>
        <div><label htmlFor={`${idp}-label`} className="mb-1 block text-xs font-medium">Label</label>
          <input id={`${idp}-label`} className={sel} maxLength={80} value={f.label} onChange={(e) => set({ label: e.target.value, ...(f.keyTouched ? {} : { key: camel(e.target.value) }) })} /></div>
        <div><label htmlFor={`${idp}-key`} className="mb-1 block text-xs font-medium">Key</label>
          <input id={`${idp}-key`} className={sel} maxLength={30} value={f.key} onChange={(e) => set({ key: e.target.value, keyTouched: true })} /></div>
        <div className="flex items-end gap-1">
          <Button variant="ghost" aria-label={`Move field ${index + 1} up`} disabled={index === 0} onClick={() => onMove(-1)}>↑</Button>
          <Button variant="ghost" aria-label={`Move field ${index + 1} down`} disabled={index === count - 1} onClick={() => onMove(1)}>↓</Button>
          <Button variant="ghost" aria-label={`Remove field ${index + 1}`} onClick={onRemove}>Remove</Button>
        </div>
      </div>
      <div className="mt-2 grid gap-2 sm:grid-cols-2">
        {(f.kind === "text" || f.kind === "textarea" || f.kind === "link" || f.kind === "media") ? (
          <div><label htmlFor={`${idp}-help`} className="mb-1 block text-xs font-medium">Help text (optional)</label><input id={`${idp}-help`} className={sel} maxLength={200} value={f.help} onChange={(e) => set({ help: e.target.value })} /></div>
        ) : null}
        {(f.kind === "text" || f.kind === "textarea" || f.kind === "link") ? (
          <div><label htmlFor={`${idp}-max`} className="mb-1 block text-xs font-medium">Maximum characters (optional)</label><input id={`${idp}-max`} type="number" min={1} max={20000} className={sel} value={f.max} onChange={(e) => set({ max: e.target.value })} /></div>
        ) : null}
        {f.kind === "select" ? (
          <div className="sm:col-span-2"><label htmlFor={`${idp}-opts`} className="mb-1 block text-xs font-medium">Options, one per line</label>
            <textarea id={`${idp}-opts`} rows={4} className={sel} value={f.options} onChange={(e) => set({ options: e.target.value })} aria-describedby={`${idp}-opts-h`} />
            <p id={`${idp}-opts-h`} className="mt-1 text-xs text-muted-foreground">Type a label, or <code>value|Label</code> to choose the stored value. The first option is the default.</p></div>
        ) : null}
        {f.kind === "number" ? (<>
          <div><label htmlFor={`${idp}-min`} className="mb-1 block text-xs font-medium">Minimum</label><input id={`${idp}-min`} type="number" className={sel} value={f.min} onChange={(e) => set({ min: e.target.value })} /></div>
          <div><label htmlFor={`${idp}-maxn`} className="mb-1 block text-xs font-medium">Maximum</label><input id={`${idp}-maxn`} type="number" className={sel} value={f.maxN} onChange={(e) => set({ maxN: e.target.value })} /></div>
        </>) : null}
        {f.kind === "list" ? (<>
          <div><label htmlFor={`${idp}-item`} className="mb-1 block text-xs font-medium">What one row is called</label><input id={`${idp}-item`} className={sel} maxLength={60} value={f.itemLabel} onChange={(e) => set({ itemLabel: e.target.value })} /></div>
          <div><label htmlFor={`${idp}-lmax`} className="mb-1 block text-xs font-medium">Most rows allowed</label><input id={`${idp}-lmax`} type="number" min={1} max={100} className={sel} value={f.listMax} onChange={(e) => set({ listMax: e.target.value })} /></div>
          <div className="sm:col-span-2">
            <p className="mb-1 text-xs font-medium">Fields in each row</p>
            <FieldList fields={f.fields} idp={`${idp}-sub`} nested onChange={(fields) => set({ fields })} />
          </div>
        </>) : null}
      </div>
    </li>
  );
}

export function FieldList({ fields, idp, nested, onChange }: { fields: EField[]; idp: string; nested?: boolean; onChange: (f: EField[]) => void }) {
  const update = (i: number, n: EField) => onChange(fields.map((x, j) => (j === i ? n : x)));
  const move = (i: number, dir: -1 | 1) => { const a = [...fields]; const j = i + dir; if (j < 0 || j >= a.length) return; [a[i], a[j]] = [a[j]!, a[i]!]; onChange(a); };
  return (
    <div className="space-y-2">
      <ul className="space-y-2">
        {fields.map((f, i) => <FieldRow key={i} f={f} idp={`${idp}-${i}`} nested={nested} index={i} count={fields.length} onChange={(n) => update(i, n)} onRemove={() => onChange(fields.filter((_, j) => j !== i))} onMove={(d) => move(i, d)} />)}
      </ul>
      <Button variant="secondary" onClick={() => onChange([...fields, blankField()])}>{nested ? "Add row field" : "Add field"}</Button>
    </div>
  );
}
