// 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";

/** CO₂ Galvo–only version (fresh submit path) */

type Target = "settings_co2gal"; // ← limited on purpose
type Opt = { id: string; label: string };
type Me = {
  id: string;
  username?: string;
  email?: string;
};

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

// ─────────────────────────────────────────────────────────────
// 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>
  );
}

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

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 useOptions(path: string, forceIncludeId?: string) {
  const [opts, setOpts] = useState<Opt[]>([]);
  const [loading, setLoading] = useState(false);
  const [q, setQ] = useState("");

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

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

      if (path === "material")                    url = `${API}/items/material?fields=id,name&limit=1000&sort=name`;
      else if (path === "material_coating")       url = `${API}/items/material_coating?fields=id,name&limit=1000&sort=name`;
      else if (path === "material_color")         url = `${API}/items/material_color?fields=id,name&limit=1000&sort=name`;
      else if (path === "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 (path === "laser_software")         url = `${API}/items/laser_software?fields=id,name&limit=1000&sort=name`;
      else if (path === "laser_source")           url = `${API}/items/laser_source?fields=submission_id,make,model&limit=2000&sort=make,model`, normalize = (rows) => rows.map((r) => ({ id: String(r.submission_id), label: [r.make, r.model].filter(Boolean).join(" ") || String(r.submission_id) }));
      else if (path === "laser_scan_lens")        url = `${API}/items/laser_scan_lens?fields=id,field_size,focal_length&limit=1000`;
      // the three fixed lists you showed (labels per your request)
      else if (path === "laser_scan_lens_config") url = `${API}/items/laser_scan_lens_config?fields=id,name&limit=1000&sort=name`;
      else if (path === "laser_scan_lens_apt")    url = `${API}/items/laser_scan_lens_apt?fields=id,name&limit=1000&sort=name`;
      else if (path === "laser_scan_lens_exp")    url = `${API}/items/laser_scan_lens_exp?fields=id,name&limit=1000&sort=name`;
      else { setOpts([]); setLoading(false); return; }

      // special label for scan lenses
      if (path === "laser_scan_lens") {
        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) };
          });
        };
      }

      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 ?? [];
      let mapped = normalize(rows);

      // include currently selected ID if not in page/filter
      if (forceIncludeId && !mapped.some((o: any) => String(o.id) === String(forceIncludeId))) {
        mapped = [{ id: String(forceIncludeId), label: "(current selection)" }, ...mapped];
      }

      const needle = (q || "").trim().toLowerCase();
      const filtered = needle ? mapped.filter((o) => o.label.toLowerCase().includes(needle)) : mapped;

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

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

  return { opts, loading, setQ };
}

function normalizeForReset(iv: any) {
  return {
    ...iv,
    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),
    lens_conf:  idToString(iv.lens_conf),
    lens_apt:   idToString(iv.lens_apt),
    lens_exp:   idToString(iv.lens_exp),
  };
}

type EditInitialValues = {
  submission_id: string | number;
  setting_title?: string;
  setting_notes?: string;
  photo?: string | { id?: string } | null;
  screen?: string | { 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;
  lens_conf?: any; lens_apt?: any; lens_exp?: any;
  fill_settings?: any[] | null;
  line_settings?: any[] | null;
  raster_settings?: any[] | null;
};

// ─────────────────────────────────────────────────────────────
// Component (CO₂ Galvo only)
// ─────────────────────────────────────────────────────────────
export default function SettingsSubmit({
  mode,
  submissionId,
  initialValues,
}: {
  mode?: "edit";
  submissionId?: string | number;
  initialValues?: EditInitialValues;
}) {
  const router = useRouter();
  const sp = useSearchParams();

  const target: Target = "settings_co2gal"; // locked

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

  // errors / me
  const [submitErr, setSubmitErr] = useState<string | null>(null);
  const [me, setMe] = useState<Me | null>(null);
  const [meErr, setMeErr] = useState<string | null>(null);

  useEffect(() => {
    let alive = true;
    fetch(`/api/me`, { cache: "no-store", credentials: "include" })
    .then((r) => (r.ok ? r.json() : Promise.reject(r)))
    .then((j) => { if (alive) setMe(j || null); })
    .catch(() => { if (alive) setMeErr("not-signed-in"); });
    return () => { alive = false; };
  }, []);

  const isEdit = mode === "edit" && submissionId != null;
  const current = useMemo(() => (isEdit && initialValues ? normalizeForReset(initialValues) : null), [isEdit, initialValues]);

  // options (galvo)
  const mats  = useOptions("material",              current?.mat);
  const coats = useOptions("material_coating",      current?.mat_coat);
  const colors= useOptions("material_color",        current?.mat_color);
  const opacs = useOptions("material_opacity",      current?.mat_opacity);
  const soft  = useOptions("laser_software",        current?.laser_soft);
  const srcs  = useOptions("laser_source",          current?.source);
  const lens  = useOptions("laser_scan_lens",       current?.lens);

  // three fixed lists (labels per your request)
  const lensConf = useOptions("laser_scan_lens_config", current?.lens_conf); // "Lens Configuration"
  const lensApt  = useOptions("laser_scan_lens_apt",    current?.lens_apt);  // "Scan Head Aperture"
  const lensExp  = useOptions("laser_scan_lens_exp",    current?.lens_exp);  // "Beam Expander"

  // form
  const {
    register,
    handleSubmit,
    control,
    reset,
    setValue,
    getValues,
    formState: { isSubmitting },
  } = useForm<any>({
    defaultValues: {
      setting_title: "",
      setting_notes: "",
      // required relations
      mat: "", mat_coat: "", mat_color: "", mat_opacity: "",
      source: "", lens: "", laser_soft: "",
      lens_conf: "", lens_apt: "", lens_exp: "",
      // numerics
      focus: "", repeat_all: "", mat_thickness: "",
      // repeaters (kept, but not required)
      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 for edit
  useEffect(() => {
    if (!isEdit || !current) return;
    reset({
      setting_title:   current.setting_title ?? "",
      setting_notes:   current.setting_notes ?? "",
      photo:           current.photo ?? null,
      screen:          current.screen ?? null,
      mat:             current.mat ?? "",
      mat_coat:        current.mat_coat ?? "",
      mat_color:       current.mat_color ?? "",
      mat_opacity:     current.mat_opacity ?? "",
      mat_thickness:   current.mat_thickness ?? "",
      source:          current.source ?? "",
      lens:            current.lens ?? "",
      focus:           current.focus ?? "",
      laser_soft:      current.laser_soft ?? "",
      repeat_all:      current.repeat_all ?? "",
      lens_conf:       current.lens_conf ?? "",
      lens_apt:        current.lens_apt ?? "",
      lens_exp:        current.lens_exp ?? "",
      fill_settings:   current.fill_settings ?? [],
      line_settings:   current.line_settings ?? [],
      raster_settings: current.raster_settings ?? [],
    });
  }, [isEdit, current, reset]);

  // keep selects stable when options hydrate
  useEffect(() => {
    if (!isEdit || !current) return;
    const names = ["mat","mat_coat","mat_color","mat_opacity","source","lens","laser_soft","lens_conf","lens_apt","lens_exp"] as const;
    const values = getValues();
    names.forEach((n) => {
      const cur = (current as any)[n];
      const now = (values as any)[n];
      if (cur && (now == null || now === "")) setValue(n as any, cur, { shouldDirty: false, shouldValidate: false });
    });
  }, [isEdit, current, getValues, setValue, mats.opts, coats.opts, colors.opts, opacs.opts, srcs.opts, lens.opts, soft.opts, lensConf.opts, lensApt.opts, lensExp.opts]);

  // numeric / bool coercers
  const num = (v: any) => (v === "" || v == null ? null : Number(v));
  const bool = (v: any) => !!v;

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

    // required-photo logic: need a file unless edit already has a photo id
    const currentPhotoId = isEdit && typeof current?.photo === "string" ? current!.photo as string : null;
    if (!currentPhotoId && !photoFile) {
      (document.querySelector('input[type="file"][data-role="photo"]') as HTMLInputElement | null)?.focus();
      return;
    }

    // build payload with only required + notes/images + repeaters
    const payload: any = {
      target,
      setting_title: values.setting_title,
      setting_notes: values.setting_notes || "",
      // required fields per your list
      source: values.source || null,
      lens: values.lens || null,
      lens_conf: values.lens_conf || null,
      lens_apt: values.lens_apt || null,
      lens_exp: values.lens_exp || null,
      focus: num(values.focus),
      mat: values.mat || null,
      mat_coat: values.mat_coat || null,
      mat_color: values.mat_color || null,
      mat_opacity: values.mat_opacity || null,
      laser_soft: values.laser_soft || null,
      repeat_all: num(values.repeat_all),
      // nice-to-have
      mat_thickness: num(values.mat_thickness),

      // server auto-sets uploader from owner, but include a mirror if available
      ...(me?.username || me?.email ? { uploader: me?.username ?? me?.email! } : {}),

      // repeaters (optional – pass-through)
      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: bool(r.cut), skip: bool(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),
      })),
    };

    // edit meta
    if (isEdit && submissionId != null) {
      payload.mode = "edit";
      payload.submission_id = submissionId;
    }

    try {
      const form = new FormData();
      form.set("payload", JSON.stringify(payload));  // server route reads "payload"

      if (photoFile)  form.set("photo",  photoFile,  photoFile.name  || "photo");
      if (screenFile) form.set("screen", screenFile, screenFile.name || "screen");

      const res = await fetch("/api/submit/settings", { method: "POST", body: form, 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");
      }

      if (!isEdit) {
        reset();
        setPhotoFile(null); setScreenFile(null);
        setPhotoPreview(""); setScreenPreview("");
      }

      const id = (data as any)?.id ? String((data as any).id) : String(submissionId ?? "");
      if (isEdit) {
        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);
  }

  const currentPhotoId = isEdit && typeof current?.photo === "string" ? (current!.photo as string) : null;
  const currentScreenId = isEdit && typeof current?.screen === "string" ? (current!.screen as string) : null;

  return (
    <div className="max-w-3xl mx-auto space-y-4">

    {/* Banner */}
    {me ? (
      <div className="text-sm text-muted-foreground">
      Submitting as <span className="font-medium">{me.username || me.email || `User ${shortId(me.id)}`}</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>
    <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>

    {/* Images */}
    <div className="grid md:grid-cols-2 gap-4">
    <div>
    <label className="block text-sm mb-1">Result Photo {!currentPhotoId ? <span className="text-red-600">*</span> : null}</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={!currentPhotoId && !photoFile} 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>

    {/* Required Selects (materials, 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>

    {/* Numeric requireds */}
    <div className="grid md:grid-cols-3 gap-3">
    <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 />
    <LabeledInput label="Material Thickness (mm)" name="mat_thickness" type="number" step="0.01" register={register} />
    <p className="text-xs text-muted-foreground md:col-span-3">0 = in focus. Negative = closer. Positive = further.</p>
    </div>

    {/* Lens Configuration block (all required) */}
    <fieldset className="border rounded p-3 space-y-2">
    <legend className="font-semibold">Lens Options</legend>
    <div className="grid md:grid-cols-3 gap-3">
    <FilterableSelect label="Lens Configuration" name="lens_conf" register={register} options={lensConf.opts} loading={lensConf.loading} onQuery={lensConf.setQ} required />
    <FilterableSelect label="Scan Head Aperture" name="lens_apt"  register={register} options={lensApt.opts}  loading={lensApt.loading}  onQuery={lensApt.setQ}  required />
    <FilterableSelect label="Beam Expander"      name="lens_exp"  register={register} options={lensExp.opts}  loading={lensExp.loading}  onQuery={lensExp.setQ}  required />
    </div>
    </fieldset>

    {/* Optional repeaters kept for parity (not required) */}
    {/* Feel free to hide these until after MVP if you want */}

    <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>
  );
}
