// components/forms/SettingsSubmit.tsx
"use client";

import { useEffect, useMemo, useState } from "react";
import { useForm, useFieldArray, type UseFormRegister } from "react-hook-form";
import { useRouter, useSearchParams } from "next/navigation";

type Target = "settings_fiber" | "settings_co2gan" | "settings_co2gal" | "settings_uv";
type Opt = { id: string; label: string };
type Me = {
  id: string;
  username?: string;
  display_name?: string;
  first_name?: string;
  last_name?: string;
  email?: string;
};

const API = (process.env.NEXT_PUBLIC_API_BASE_URL || "").replace(/\/$/, "");

// ─────────────────────────────────────────────────────────────
// Local enums (no schema introspection)
// ─────────────────────────────────────────────────────────────
const FILL_TYPE_OPTIONS = [
  { label: "UniDirectional", value: "uni" },
{ label: "BiDirectional", value: "bi" },
{ label: "Offset Fill", value: "offset" },
];

const RASTER_TYPE_OPTIONS = [
  { label: "UniDirectional", value: "uni" },
{ label: "BiDirectional", value: "bi" },
{ label: "Offset Fill", value: "offset" },
];

const RASTER_DITHER_OPTIONS = [
  { label: "Threshold", value: "threshold" },
{ label: "Ordered", value: "ordered" },
{ label: "Atkinson", value: "atkinson" },
{ label: "Dither", value: "dither" },
{ label: "Stucki", value: "stucki" },
{ label: "Jarvis", value: "jarvis" },
{ label: "Newsprint", value: "newsprint" },
{ label: "Halftone", value: "halftone" },
{ label: "Sketch", value: "sketch" },
{ label: "Grayscale", value: "grayscale" },
];

const toOpts = (arr: { label: string; value: string }[]): Opt[] =>
arr.map((x) => ({ id: x.value, label: x.label }));

function shortId(s?: string) {
  if (!s) return "";
  return s.length <= 12 ? s : `${s.slice(0, 8)}…${s.slice(-4)}`;
}

// ─────────────────────────────────────────────────────────────
/** Normalizers for edit-mode prefill (IDs + enums) */
// ─────────────────────────────────────────────────────────────
function idToString(v: any): string {
  if (v == null || v === "") return "";
  if (typeof v === "object") {
    if ((v as any).id != null) return String((v as any).id);
    if ((v as any).submission_id != null) return String((v as any).submission_id);
  }
  return String(v);
}

function normalizeEnums(value: any, allowed: string[], fallback: string) {
  const v = value == null ? "" : String(value).toLowerCase();
  return allowed.includes(v) ? v : fallback;
}

type BaseProps = { initialTarget?: Target };

type EditInitialValues = {
  setting_title?: string;
  setting_notes?: string;

  photo?: string | File | { id?: string } | null;
  screen?: string | File | { id?: string } | null;

  mat?: any;
  mat_coat?: any;
  mat_color?: any;
  mat_opacity?: any;
  mat_thickness?: number | null;

  source?: any;
  lens?: any;
  focus?: number | null;

  laser_soft?: any;
  repeat_all?: number | null;

  fill_settings?: any[] | null;
  line_settings?: any[] | null;
  raster_settings?: any[] | null;
};

function normalizeForReset(iv: EditInitialValues) {
  return {
    ...iv,
    // Single-selects → string IDs
    mat: idToString(iv.mat),
    mat_coat: idToString(iv.mat_coat),
    mat_color: idToString(iv.mat_color),
    mat_opacity: idToString(iv.mat_opacity),
    source: idToString(iv.source),
    lens: idToString(iv.lens),
    laser_soft: idToString(iv.laser_soft),

    // Arrays: coerce dropdown-ish fields to internal enum keys
    fill_settings: (iv.fill_settings ?? []).map((r: any) => ({
      ...r,
      type: normalizeEnums(r?.type, ["uni", "bi", "offset"], "uni"),
    })),
    raster_settings: (iv.raster_settings ?? []).map((r: any) => ({
      ...r,
      type: normalizeEnums(r?.type, ["uni", "bi", "offset"], "uni"),
                                                                 dither: normalizeEnums(
                                                                   r?.dither,
                                                                   [
                                                                     "threshold",
                                                                     "ordered",
                                                                     "atkinson",
                                                                     "dither",
                                                                     "stucki",
                                                                     "jarvis",
                                                                     "newsprint",
                                                                     "halftone",
                                                                     "sketch",
                                                                     "grayscale",
                                                                   ],
                                                                   "threshold"
                                                                 ),
    })),
    line_settings: (iv.line_settings ?? []).map((r: any) => ({ ...r })),
  };
}

// ─────────────────────────────────────────────────────────────
// Props (Create vs Edit) + type guard
// ─────────────────────────────────────────────────────────────
type CreateProps = BaseProps & {
  mode?: "create";
  submissionId?: never;
  initialValues?: never;
};

type EditProps = BaseProps & {
  mode: "edit";
  submissionId: string | number;
  initialValues: EditInitialValues;
};

function isEditProps(p: CreateProps | EditProps): p is EditProps {
  return (p as any)?.mode === "edit";
}

// ─────────────────────────────────────────────────────────────
// Options loader (materials, lenses, etc.)
// ─────────────────────────────────────────────────────────────
function useOptions(path: string, forceIncludeId?: string, opts?: { disableNmFilter?: boolean }) {
  const [optsState, setOptsState] = useState<Opt[]>([]);
  const [loading, setLoading] = useState(false);
  const [q, setQ] = useState("");

  const disableNmFilter = opts?.disableNmFilter === true;

  // helpers for the "laser_source" nm filtering
  const parseNum = (v: any): number | null => {
    if (v == null) return null;
    const m = String(v).match(/(\d+(\.\d+)?)/);
    return m ? Number(m[1]) : null;
  };

  const nmRangeFor = (target?: string | null): [number, number] | null => {
    if (!target) return null;
    const t = target.toLowerCase();
    if (t === "fiber") return [1000, 9000];
    if (t === "uv") return [300, 400];
    if (t === "co2-gantry" || t === "co2-galvo") return [10000, 11000];
    return null;
  };

  useEffect(() => {
    let alive = true;
    setLoading(true);

    (async () => {
      const [rawPath, qs] = path.split("?", 2);
      const params = new URLSearchParams(qs || "");
      const target = params.get("target") || "";

      let url = "";
      let normalize: (rows: any[]) => Opt[] = (rows) =>
      rows.map((r) => ({
        id: String(r.id),
                       label: String(r.name ?? r.label ?? r.title ?? r.value ?? r.id),
      }));

      if (rawPath === "material") {
        url = `${API}/items/material?fields=id,name&limit=1000&sort=name`;
      } else if (rawPath === "material_color") {
        url = `${API}/items/material_color?fields=id,name&limit=1000&sort=name`;
      } else if (rawPath === "material_coating") {
        url = `${API}/items/material_coating?fields=id,name&limit=1000&sort=name`;
      } else if (rawPath === "material_opacity") {
        url = `${API}/items/material_opacity?fields=id,opacity&limit=1000&sort=opacity`;
        normalize = (rows) => rows.map((r) => ({ id: String(r.id), label: String(r.opacity ?? r.id) }));
      } else if (rawPath === "laser_software") {
        url = `${API}/items/laser_software?fields=id,name&limit=1000&sort=name`;
      } else if (rawPath === "laser_source") {
        url = `${API}/items/laser_source?fields=submission_id,make,model,nm&limit=2000&sort=make,model`;
        const range = disableNmFilter ? null : nmRangeFor(target);
        normalize = (rows) => {
          const filtered = range
          ? rows.filter((r: any) => {
            const nm = parseNum(r.nm);
            return nm != null && nm >= range[0] && nm <= range[1];
          })
          : rows;
          return filtered.map((r: any) => ({
            id: String(r.submission_id),
                                           label: [r.make, r.model].filter(Boolean).join(" ") || String(r.submission_id),
          }));
        };
      } else if (rawPath === "lens") {
        // CO2 gantry uses focus lenses; all others use scan lenses
        if (target === "co2-gantry") {
          url = `${API}/items/laser_focus_lens?fields=id,name&limit=1000`;
          normalize = (rows) => rows.map((r) => ({ id: String(r.id), label: String(r.name ?? r.id) }));
        } else {
          // SCAN LENSES (fiber, uv, co2-galvo): sort numerically by focal_length
          url = `${API}/items/laser_scan_lens?fields=id,field_size,focal_length&limit=1000`;
          normalize = (rows) => {
            const toNum = (v: any) => {
              const m = String(v ?? "").match(/-?\d+(\.\d+)?/);
              return m ? parseFloat(m[0]) : Number.POSITIVE_INFINITY;
            };
            const sorted = [...rows].sort((a, b) => toNum(a.focal_length) - toNum(b.focal_length));
            return sorted.map((r) => {
              const fs = r.field_size != null ? `${r.field_size}` : "";
              const fl = r.focal_length != null ? `${r.focal_length}` : "";
              const composed = [fs && `${fs} mm`, fl && `${fl} mm`].filter(Boolean).join(" — ");
              return { id: String(r.id), label: composed || String(r.id) };
            });
          };
        }
      } else {
        // unknown path → empty
        setOptsState([]);
        setLoading(false);
        return;
      }

      const res = await fetch(url, { cache: "no-store", credentials: "include" });
      if (!res.ok) throw new Error(`Directus ${res.status} fetching ${url}`);
      const json = await res.json();
      const rows = json?.data ?? [];
      const mapped = normalize(rows);

      // Ensure the currently selected value is present even if filters/pagination miss it
      let ensured = mapped;
      if (forceIncludeId && !mapped.some((o: any) => String(o.id) === String(forceIncludeId))) {
        ensured = [{ id: String(forceIncludeId), label: "(current selection)" }, ...mapped];
      }

      // client-side text filter
      const needle = (q || "").trim().toLowerCase();
      const filtered = needle ? ensured.filter((o) => o.label.toLowerCase().includes(needle)) : ensured;

      if (alive) setOptsState(filtered);
    })()
    .catch(() => alive && setOptsState([]))
    .finally(() => alive && setLoading(false));

    return () => {
      alive = false;
    };
  }, [path, q, forceIncludeId, disableNmFilter]);

  return { opts: optsState, loading, setQ };
}

// ─────────────────────────────────────────────────────────────
// Small UI bits
// ─────────────────────────────────────────────────────────────
function FilterableSelect({
  label,
  name,
  register,
  options,
  loading,
  onQuery,
  placeholder = "—",
  required = false,
}: {
  label: string;
  name: string;
  register: UseFormRegister<any>;
  options: Opt[];
  loading?: boolean;
  onQuery?: (q: string) => void;
  placeholder?: string;
  required?: boolean;
}) {
  const [filter, setFilter] = useState("");
  useEffect(() => {
    onQuery?.(filter);
  }, [filter, onQuery]);

  const filtered = useMemo(() => {
    if (!filter) return options;
    const f = filter.toLowerCase();
    return options.filter((o) => o.label.toLowerCase().includes(f));
  }, [options, filter]);

  return (
    <div>
    <label className="block text-sm mb-1">
    {label} {required ? <span className="text-red-600">*</span> : null}
    </label>
    <input
    className="w-full border rounded px-2 py-1 mb-1"
    placeholder="Type to filter…"
    value={filter}
    onChange={(e) => setFilter(e.target.value)}
    />
    <select className="w-full border rounded px-2 py-1" {...register(name, { required })}>
    <option value="">
    {placeholder}
    {loading ? " (loading…)" : ""}
    </option>
    {filtered.map((o) => (
      <option key={o.id} value={o.id}>
      {o.label}
      </option>
    ))}
    </select>
    </div>
  );
}

function BoolBox({ label, name, register }: { label: string; name: string; register: UseFormRegister<any> }) {
  return (
    <label className="flex items-center gap-1 text-sm">
    <input type="checkbox" {...register(name)} /> {label}
    </label>
  );
}

function LabeledInput({
  label,
  name,
  type = "text",
  step,
  register,
  required = false,
  min,
  max,
}: {
  label: string;
  name: string;
  type?: "text" | "number";
  step?: string | number;
  register: UseFormRegister<any>;
  required?: boolean;
  min?: number;
  max?: number;
}) {
  return (
    <div>
    <label className="block text-xs mb-1">
    {label}
    {required ? " *" : ""}
    </label>
    <input
    type={type}
    step={step}
    min={min}
    max={max}
    className="w-full border rounded px-2 py-1"
    {...register(name, { required })}
    />
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Component
// ─────────────────────────────────────────────────────────────
export default function SettingsSubmit(props: CreateProps | EditProps) {
  const router = useRouter();
  const sp = useSearchParams();

  const isEdit = isEditProps(props);
  const edit = isEdit ? props : null; // strongly-typed local when edit

  // Initialize as CO2-galvo in edit mode (unless explicitly overridden)
  const initialFromQuery =
  (sp.get("target") as Target) ||
  props.initialTarget ||
  (isEdit ? "settings_co2gal" : "settings_fiber");
  const [target, setTarget] = useState<Target>(initialFromQuery);

  useEffect(() => {
    if (isEdit && props.initialTarget && props.initialTarget !== target) {
      setTarget(props.initialTarget);
    }
  }, [isEdit, props.initialTarget, target]);

  // Map collection -> slug used by options selectors
  const typeForOptions = useMemo(() => {
    switch (target) {
      case "settings_fiber":
        return "fiber";
      case "settings_uv":
        return "uv";
      case "settings_co2gan":
        return "co2-gantry";
      case "settings_co2gal":
        return "co2-galvo";
      default:
        return "fiber";
    }
  }, [target]);

  // Image inputs
  const [photoFile, setPhotoFile] = useState<File | null>(null);
  const [screenFile, setScreenFile] = useState<File | null>(null);
  const [photoPreview, setPhotoPreview] = useState<string>("");
  const [screenPreview, setScreenPreview] = useState<string>("");

  // UX error for auth/submit
  const [submitErr, setSubmitErr] = useState<string | null>(null);

  // Current signed-in user (banner only)
  const [me, setMe] = useState<Me | null>(null);
  const [meErr, setMeErr] = useState<string | null>(null);

  useEffect(() => {
    let alive = true;

    // use our bearer-only API
    fetch(`/api/me`, { cache: "no-store", credentials: "include" })
    .then((r) => (r.ok ? r.json() : Promise.reject(r)))
    .then((j) => {
      if (!alive) return;
      setMe(j || null);
    })
    .catch(() => {
      if (alive) setMeErr("not-signed-in");
    });

      return () => {
        alive = false;
      };
  }, []);

  const meLabel = me?.username ?? "";

  // For edit-mode, compute normalized current values once to seed option lists
  const current = useMemo(
    () => (isEdit && edit?.initialValues ? normalizeForReset(edit.initialValues) : null),
                          [isEdit, edit?.initialValues]
  );

  // Options
  const mats = useOptions("material", current?.mat || undefined);
  const coats = useOptions("material_coating", current?.mat_coat || undefined);
  const colors = useOptions("material_color", current?.mat_color || undefined);
  const opacs = useOptions("material_opacity", current?.mat_opacity || undefined);
  const soft = useOptions("laser_software", current?.laser_soft || undefined); // required for ALL targets

  // these two need ?target=
  const srcs = useOptions(`laser_source?target=${typeForOptions}`, current?.source || undefined, {
    disableNmFilter: isEdit, // show the exact current source even if nm is out-of-range
  });
  const lens = useOptions(`lens?target=${typeForOptions}`, current?.lens || undefined);

  // Repeater choice options (LOCAL now, no network)
  const fillType = { opts: toOpts(FILL_TYPE_OPTIONS), loading: false, setQ: (_: string) => {} };
  const rasterType = { opts: toOpts(RASTER_TYPE_OPTIONS), loading: false, setQ: (_: string) => {} };
  const rasterDither = { opts: toOpts(RASTER_DITHER_OPTIONS), loading: false, setQ: (_: string) => {} };

  const {
    register,
    handleSubmit,
    control,
    reset,
    formState: { isSubmitting },
  } = useForm<any>({
    defaultValues: {
      setting_title: "",
      setting_notes: "",
      mat: "",
      mat_coat: "",
      mat_color: "",
      mat_opacity: "",
      mat_thickness: "",
      source: "",
      lens: "",
      focus: "",
      laser_soft: "",
      repeat_all: "", // on all targets
      fill_settings: [],
      line_settings: [],
      raster_settings: [],
    },
  });

  const fills = useFieldArray({ control, name: "fill_settings" });
  const lines = useFieldArray({ control, name: "line_settings" });
  const rasters = useFieldArray({ control, name: "raster_settings" });

  // Prefill the form in edit mode
  useEffect(() => {
    if (isEdit && edit?.initialValues) {
      const iv = normalizeForReset(edit.initialValues);
      reset({
        setting_title: iv.setting_title ?? "",
        setting_notes: iv.setting_notes ?? "",
        photo: iv.photo ?? null,
        screen: iv.screen ?? null,
        mat: iv.mat ?? "",
        mat_coat: iv.mat_coat ?? "",
        mat_color: iv.mat_color ?? "",
        mat_opacity: iv.mat_opacity ?? "",
        mat_thickness: iv.mat_thickness ?? "",
        source: iv.source ?? "",
        lens: iv.lens ?? "",
        focus: iv.focus ?? "",
        laser_soft: iv.laser_soft ?? "",
        repeat_all: iv.repeat_all ?? "",
        fill_settings: iv.fill_settings ?? [],
        line_settings: iv.line_settings ?? [],
        raster_settings: iv.raster_settings ?? [],
      });
    }
  }, [isEdit, edit?.initialValues, reset]);

  function num(v: any) {
    return v === "" || v == null ? null : Number(v);
  }
  const bool = (v: any) => !!v;

  async function onSubmit(values: any) {
    setSubmitErr(null);

    // In edit mode, allow keeping the existing photo (no new file) if one exists.
    const hasExistingPhotoId =
    !!(isEdit && typeof edit!.initialValues?.photo === "string" && edit!.initialValues.photo);
    if (!photoFile && !hasExistingPhotoId && !isEdit) {
      (document.querySelector('input[type="file"][data-role="photo"]') as HTMLInputElement | null)?.focus();
      return;
    }

    const payload: any = {
      target,
      setting_title: values.setting_title,
      setting_notes: values.setting_notes || "",
      mat: values.mat || null,
      mat_coat: values.mat_coat || null,
      mat_color: values.mat_color || null,
      mat_opacity: values.mat_opacity || null,
      mat_thickness: num(values.mat_thickness),
      source: values.source || null,
      lens: values.lens || null,
      focus: num(values.focus),
      laser_soft: values.laser_soft || null, // all targets
      repeat_all: num(values.repeat_all), // all targets
      fill_settings: (values.fill_settings || []).map((r: any) => ({
        name: r.name || "",
        power: num(r.power),
                                                                   speed: num(r.speed),
                                                                   interval: num(r.interval),
                                                                   pass: num(r.pass),
                                                                   type: r.type || "",
                                                                   frequency: num(r.frequency),
                                                                   pulse: num(r.pulse),
                                                                   angle: num(r.angle),
                                                                   auto: bool(r.auto),
                                                                   increment: num(r.increment),
                                                                   cross: bool(r.cross),
                                                                   flood: bool(r.flood),
                                                                   air: bool(r.air),
      })),
      line_settings: (values.line_settings || []).map((r: any) => ({
        name: r.name || "",
        power: num(r.power),
                                                                   speed: num(r.speed),
                                                                   perf: bool(r.perf),
                                                                   cut: r.cut || "",
                                                                   skip: r.skip || "",
                                                                   pass: num(r.pass),
                                                                   air: bool(r.air),
                                                                   frequency: num(r.frequency),
                                                                   pulse: num(r.pulse),
                                                                   wobble: bool(r.wobble),
                                                                   step: num(r.step),
                                                                   size: num(r.size),
      })),
      raster_settings: (values.raster_settings || []).map((r: any) => ({
        name: r.name || "",
        power: num(r.power),
                                                                       speed: num(r.speed),
                                                                       type: r.type || "",
                                                                       dither: r.dither || "",
                                                                       halftone_cell: num(r.halftone_cell),
                                                                       halftone_angle: num(r.halftone_angle),
                                                                       inversion: bool(r.inversion),
                                                                       interval: num(r.interval),
                                                                       dot: num(r.dot),
                                                                       pass: num(r.pass),
                                                                       air: bool(r.air),
                                                                       frequency: num(r.frequency),
                                                                       pulse: num(r.pulse),
                                                                       cross: bool(r.cross),
      })),
    };

    // Ensure EDIT gets routed as a PATCH via the API
    if (isEdit && edit?.submissionId != null) {
      payload.mode = "edit";
      payload.submission_id = edit.submissionId;
    }

    try {
      let res: Response;

      if (photoFile || screenFile) {
        const form = new FormData();
        form.set("payload", JSON.stringify(payload));
        if (photoFile) form.set("photo", photoFile, photoFile.name || "photo");
        if (screenFile) form.set("screen", screenFile, screenFile.name || "screen");
        res = await fetch("/api/submit/settings", { method: "POST", body: form, credentials: "include" });
      } else {
        res = await fetch("/api/submit/settings", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload),
                          credentials: "include",
        });
      }

      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        if (res.status === 401 || res.status === 403) throw new Error("You must be signed in to submit settings.");
        throw new Error((data as any)?.error || "Submission failed");
      }

      // Success
      if (!isEdit) {
        // reset only on create
        reset();
        setPhotoFile(null);
        setScreenFile(null);
        setPhotoPreview("");
        setScreenPreview("");
      }

      const id = (data as any)?.id ? String((data as any).id) : String(edit?.submissionId ?? "");
      // back to success (create) or view (edit)
      if (isEdit) {
        // remove ?edit=1
        const q = new URLSearchParams(sp.toString());
        q.delete("edit");
        router.replace(`/portal/laser-settings?${q.toString()}`);
      } else {
        router.push(`/submit/settings/success?target=${encodeURIComponent(target)}&id=${encodeURIComponent(id)}`);
      }
    } catch (e: any) {
      setSubmitErr(e?.message || "Submission failed");
    }
  }

  function onPick(file: File | null, setFile: (f: File | null) => void, setPreview: (s: string) => void) {
    setFile(file);
    if (!file) {
      setPreview("");
      return;
    }
    const reader = new FileReader();
    reader.onload = () => setPreview(String(reader.result || ""));
    reader.readAsDataURL(file);
  }

  // Convenience strings for “Current:” (edit mode)
  const currentPhotoId =
  isEdit && typeof edit.initialValues?.photo === "string" ? (edit.initialValues.photo as string) : null;
  const currentScreenId =
  isEdit && typeof edit.initialValues?.screen === "string" ? (edit.initialValues.screen as string) : null;

  return (
    <div className="max-w-3xl mx-auto space-y-4">
    {/* Target + Software (Software required for ALL targets) */}
    <div className="flex flex-wrap gap-3 items-end">
    <div>
    <label className="block text-sm mb-1">Target</label>
    <select
    className="border rounded px-2 py-1"
    value={target}
    onChange={(e) => setTarget(e.target.value as Target)}
    >
    <option value="settings_fiber">Fiber</option>
    <option value="settings_co2gan">CO₂ Gantry</option>
    <option value="settings_co2gal">CO₂ Galvo</option>
    <option value="settings_uv">UV</option>
    </select>
    </div>

    <div className="flex-1 min-w-[220px]">
    <FilterableSelect
    label="Software"
    name="laser_soft"
    register={register}
    options={soft.opts}
    loading={soft.loading}
    onQuery={soft.setQ}
    required={true}
    />
    </div>
    </div>

    {/* Submitting-as banner */}
    {me ? (
      <div className="text-sm text-muted-foreground">
      Submitting as <span className="font-medium">{meLabel}</span>.
      </div>
    ) : meErr ? (
      <div className="border border-yellow-600 bg-yellow-50 text-yellow-800 rounded p-2 text-sm">
      You’re not signed in. Submissions will fail until you sign in.
      </div>
    ) : null}

    {submitErr ? (
      <div className="border border-red-500 text-red-600 bg-red-50 rounded p-2 text-sm">{submitErr}</div>
    ) : null}

    <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
    {/* Title */}
    <div className="grid md:grid-cols-2 gap-3">
    <div className="md:col-span-2">
    <label className="block text-sm mb-1">
    Title <span className="text-red-600">*</span>
    </label>
    <input className="w-full border rounded px-2 py-1" {...register("setting_title", { required: true })} />
    </div>
    </div>

    {/* Images */}
    <div className="grid md:grid-cols-2 gap-4">
    <div>
    <label className="block text-sm mb-1">
    Result Photo {isEdit ? null : <span className="text-red-600">*</span>}
    </label>

    {currentPhotoId && (
      <p className="text-xs text-muted-foreground mb-1">
      Current: <span className="font-mono">{shortId(currentPhotoId)}</span>
      </p>
    )}

    <input
    type="file"
    accept="image/*"
    data-role="photo"
    required={!isEdit && !currentPhotoId}
    onChange={(e) => onPick(e.target.files?.[0] ?? null, setPhotoFile, setPhotoPreview)}
    />
    <p className="text-xs text-muted-foreground mt-1">
    {photoFile ? (
      <>
      Selected: <span className="font-mono">{photoFile.name}</span>
      </>
    ) : (
      "Max 25 MB. JPG/PNG/WebP recommended."
    )}
    </p>
    {photoPreview ? <img src={photoPreview} alt="Result preview" className="mt-2 rounded border" /> : null}
    </div>

    <div>
    <label className="block text-sm mb-1">Settings Screenshot (optional)</label>

    {currentScreenId && (
      <p className="text-xs text-muted-foreground mb-1">
      Current: <span className="font-mono">{shortId(currentScreenId)}</span>
      </p>
    )}

    <input
    type="file"
    accept="image/*"
    onChange={(e) => onPick(e.target.files?.[0] ?? null, setScreenFile, setScreenPreview)}
    />
    <p className="text-xs text-muted-foreground mt-1">
    {screenFile ? (
      <>
      Selected: <span className="font-mono">{screenFile.name}</span>
      </>
    ) : (
      "Max 25 MB. JPG/PNG/WebP recommended."
    )}
    </p>
    {screenPreview ? <img src={screenPreview} alt="Settings preview" className="mt-2 rounded border" /> : null}
    </div>
    </div>

    {/* Notes */}
    <div>
    <label className="block text-sm mb-1">Notes</label>
    <textarea rows={4} className="w-full border rounded px-2 py-1" {...register("setting_notes")} />
    </div>

    {/* Material / Source / Lens */}
    <div className="grid md:grid-cols-2 gap-3">
    <FilterableSelect
    label="Material"
    name="mat"
    register={register}
    options={mats.opts}
    loading={mats.loading}
    onQuery={mats.setQ}
    required
    />
    <FilterableSelect
    label="Coating"
    name="mat_coat"
    register={register}
    options={coats.opts}
    loading={coats.loading}
    onQuery={coats.setQ}
    required
    />
    <FilterableSelect
    label="Color"
    name="mat_color"
    register={register}
    options={colors.opts}
    loading={colors.loading}
    onQuery={colors.setQ}
    required
    />
    <FilterableSelect
    label="Opacity"
    name="mat_opacity"
    register={register}
    options={opacs.opts}
    loading={opacs.loading}
    onQuery={opacs.setQ}
    required
    />
    <FilterableSelect
    label="Laser Source"
    name="source"
    register={register}
    options={srcs.opts}
    loading={srcs.loading}
    onQuery={srcs.setQ}
    required
    />
    <FilterableSelect
    label="Lens"
    name="lens"
    register={register}
    options={lens.opts}
    loading={lens.loading}
    onQuery={lens.setQ}
    required
    />
    </div>

    {/* Focus, thickness, repeat_all */}
    <div className="grid md:grid-cols-3 gap-3">
    <LabeledInput label="Material Thickness (mm)" name="mat_thickness" type="number" step="0.01" register={register} />
    <LabeledInput label="Focus (mm)" name="focus" type="number" min={-10} max={10} step="1" register={register} required />
    <LabeledInput label="Repeat All" name="repeat_all" type="number" step="1" register={register} required />
    <p className="text-xs text-muted-foreground md:col-span-3">
    0 = in focus. Negative = focus closer. Positive = focus further.
    </p>
    </div>

    {/* FILL */}
    <fieldset className="border rounded p-3 space-y-2">
    <div className="flex items-center justify-between">
    <legend className="font-semibold">Fill Settings</legend>
    <button type="button" className="px-2 py-1 border rounded" onClick={() => fills.append({ type: "uni" })}>
    + Add
    </button>
    </div>
    {fills.fields.map((f, i) => (
      <div key={f.id} className="grid md:grid-cols-4 gap-2">
      <LabeledInput label="Name" name={`fill_settings.${i}.name`} register={register} />
      <FilterableSelect
      label="Type"
      name={`fill_settings.${i}.type`}
      register={register}
      options={fillType.opts}
      loading={false}
      onQuery={() => {}}
      placeholder="Select type"
      />
      <LabeledInput label="Frequency (kHz)" name={`fill_settings.${i}.frequency`} type="number" step="0.1" register={register} />
      <LabeledInput label="Pulse (ns)" name={`fill_settings.${i}.pulse`} type="number" step="0.1" register={register} />
      <LabeledInput label="Power (%)" name={`fill_settings.${i}.power`} type="number" step="0.1" register={register} />
      <LabeledInput label="Speed (mm/s)" name={`fill_settings.${i}.speed`} type="number" step="0.1" register={register} />
      <LabeledInput label="Interval (mm)" name={`fill_settings.${i}.interval`} type="number" step="0.001" register={register} />
      <LabeledInput label="Pass" name={`fill_settings.${i}.pass`} type="number" step="1" register={register} />
      <LabeledInput label="Angle (°)" name={`fill_settings.${i}.angle`} type="number" step="1" register={register} />
      <LabeledInput label="Increment" name={`fill_settings.${i}.increment`} type="number" step="0.001" register={register} />
      <div className="flex items-center gap-3">
      <BoolBox label="Auto" name={`fill_settings.${i}.auto`} register={register} />
      <BoolBox label="Cross" name={`fill_settings.${i}.cross`} register={register} />
      </div>
      <div className="flex items-center gap-3">
      <BoolBox label="Flood" name={`fill_settings.${i}.flood`} register={register} />
      <BoolBox label="Air" name={`fill_settings.${i}.air`} register={register} />
      </div>

      <button type="button" className="px-2 py-1 border rounded md:col-span-4" onClick={() => fills.remove(i)}>
      Remove
      </button>
      </div>
    ))}
    </fieldset>

    {/* LINE */}
    <fieldset className="border rounded p-3 space-y-2">
    <div className="flex items-center justify-between">
    <legend className="font-semibold">Line Settings</legend>
    <button type="button" className="px-2 py-1 border rounded" onClick={() => lines.append({})}>
    + Add
    </button>
    </div>
    {lines.fields.map((f, i) => (
      <div key={f.id} className="grid md:grid-cols-4 gap-2">
      <LabeledInput label="Name" name={`line_settings.${i}.name`} register={register} />
      <LabeledInput label="Frequency (kHz)" name={`line_settings.${i}.frequency`} type="number" step="0.1" register={register} />
      <LabeledInput label="Pulse (ns)" name={`line_settings.${i}.pulse`} type="number" step="0.1" register={register} />
      <LabeledInput label="Power (%)" name={`line_settings.${i}.power`} type="number" step="0.1" register={register} />
      <LabeledInput label="Speed (mm/s)" name={`line_settings.${i}.speed`} type="number" step="0.1" register={register} />
      <LabeledInput label="Perf" name={`line_settings.${i}.perf`} register={register} />
      <LabeledInput label="Cut" name={`line_settings.${i}.cut`} register={register} />
      <LabeledInput label="Skip" name={`line_settings.${i}.skip`} register={register} />
      <LabeledInput label="Pass" name={`line_settings.${i}.pass`} type="number" step="1" register={register} />
      <LabeledInput label="Step" name={`line_settings.${i}.step`} type="number" step="0.001" register={register} />
      <LabeledInput label="Size" name={`line_settings.${i}.size`} type="number" step="0.001" register={register} />
      <BoolBox label="Wobble" name={`line_settings.${i}.wobble`} register={register} />
      <BoolBox label="Air" name={`line_settings.${i}.air`} register={register} />

      <button type="button" className="px-2 py-1 border rounded md:col-span-4" onClick={() => lines.remove(i)}>
      Remove
      </button>
      </div>
    ))}
    </fieldset>

    {/* RASTER */}
    <fieldset className="border rounded p-3 space-y-2">
    <div className="flex items-center justify-between">
    <legend className="font-semibold">Raster Settings</legend>
    <button
    type="button"
    className="px-2 py-1 border rounded"
    onClick={() => rasters.append({ type: "uni", dither: "threshold" })}
    >
    + Add
    </button>
    </div>
    {rasters.fields.map((f, i) => (
      <div key={f.id} className="grid md:grid-cols-4 gap-2">
      <LabeledInput label="Name" name={`raster_settings.${i}.name`} register={register} />
      <LabeledInput label="Frequency (kHz)" name={`raster_settings.${i}.frequency`} type="number" step="0.1" register={register} />
      <LabeledInput label="Pulse (ns)" name={`raster_settings.${i}.pulse`} type="number" step="0.1" register={register} />
      <FilterableSelect
      label="Type"
      name={`raster_settings.${i}.type`}
      register={register}
      options={rasterType.opts}
      loading={false}
      onQuery={() => {}}
      placeholder="Select type"
      />
      <FilterableSelect
      label="Dither"
      name={`raster_settings.${i}.dither`}
      register={register}
      options={rasterDither.opts}
      loading={false}
      onQuery={() => {}}
      placeholder="Select dither"
      />
      <LabeledInput label="Power (%)" name={`raster_settings.${i}.power`} type="number" step="0.1" register={register} />
      <LabeledInput label="Speed (mm/s)" name={`raster_settings.${i}.speed`} type="number" step="0.1" register={register} />
      <LabeledInput label="Halftone Cell" name={`raster_settings.${i}.halftone_cell`} type="number" step="1" register={register} />
      <LabeledInput label="Halftone Angle" name={`raster_settings.${i}.halftone_angle`} type="number" step="1" register={register} />
      <LabeledInput label="Interval (mm)" name={`raster_settings.${i}.interval`} type="number" step="0.001" register={register} />
      <LabeledInput label="Dot" name={`raster_settings.${i}.dot`} type="number" step="0.1" register={register} />
      <LabeledInput label="Pass" name={`raster_settings.${i}.pass`} type="number" step="1" register={register} />
      <BoolBox label="Cross" name={`raster_settings.${i}.cross`} register={register} />
      <div className="flex items-center gap-3">
      <BoolBox label="Inversion" name={`raster_settings.${i}.inversion`} register={register} />
      <BoolBox label="Air" name={`raster_settings.${i}.air`} register={register} />
      </div>

      <button type="button" className="px-2 py-1 border rounded md:col-span-4" onClick={() => rasters.remove(i)}>
      Remove
      </button>
      </div>
    ))}
    </fieldset>

    <button
    disabled={isSubmitting}
    className="px-3 py-2 border rounded bg-accent text-background hover:opacity-90 disabled:opacity-50"
    >
    {isSubmitting ? "Submitting…" : isEdit ? "Save Changes" : "Submit Settings"}
    </button>
    </form>
    </div>
  );
}
