"use client";

import { ReactNode, useEffect, useState } from "react";
import { ApiError, get, put } from "@/lib/api";
import { Field, Notice, Spinner } from "@/components/ui";

export type NumericField = { key: string; label: string; hint?: string; step?: string; info?: ReactNode };
export type JsonField = { key: string; label: string; hint?: string; rows?: number; info?: ReactNode };

type SettingsResponse = { settings: Record<string, any> };

/**
 * Reusable runtime-settings form. Each instance edits only the fields it is given
 * and PUTs just that subset (the backend merges), so the Admin Settings page can
 * split the single settings document across the Runtime and Cost & Quality tabs.
 */
export default function SettingsForm({
  numericFields,
  jsonFields = [],
  includeLanguage = false,
  intro,
}: {
  numericFields: NumericField[];
  jsonFields?: JsonField[];
  includeLanguage?: boolean;
  intro?: ReactNode;
}) {
  const [settings, setSettings] = useState<Record<string, any> | null>(null);
  const [language, setLanguage] = useState("de_CH");
  const [errors, setErrors] = useState<string[]>([]);
  const [saved, setSaved] = useState(false);
  const [loadError, setLoadError] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);

  useEffect(() => {
    get<SettingsResponse>("settings")
      .then((d) => {
        setSettings(d.settings);
        setLanguage(String(d.settings["runtime.active_language"] ?? "de_CH"));
      })
      .catch((e) => setLoadError((e as Error).message));
  }, []);

  if (loadError) return <Notice kind="error">Could not load settings: {loadError}</Notice>;
  if (!settings) return <Spinner label="Loading settings…" />;

  async function save(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setBusy(true);
    setErrors([]);
    setSaved(false);
    const form = new FormData(e.currentTarget);
    const payload: Record<string, any> = {};
    if (includeLanguage) payload["runtime.active_language"] = language;

    for (const f of numericFields) {
      const raw = String(form.get(f.key) ?? "").trim();
      if (raw !== "") payload[f.key] = f.step ? parseFloat(raw) : parseInt(raw, 10);
    }
    for (const f of jsonFields) {
      const raw = String(form.get(f.key) ?? "").trim();
      if (raw !== "") {
        try {
          payload[f.key] = JSON.parse(raw);
        } catch {
          setErrors((p) => [...p, `${f.label}: invalid JSON`]);
          setBusy(false);
          return;
        }
      }
    }

    try {
      const res = await put<SettingsResponse>("settings", { settings: payload });
      setSettings(res.settings);
      setSaved(true);
    } catch (err) {
      if (err instanceof ApiError && err.errors.length) setErrors(err.errors);
      else setErrors([(err as Error).message]);
    } finally {
      setBusy(false);
    }
  }

  return (
    <>
      {intro && <p className="mb-4 text-sm text-slate-600">{intro}</p>}
      {saved && <div className="mb-4"><Notice kind="success">Settings saved.</Notice></div>}
      {errors.length > 0 && (
        <div className="mb-4">
          <Notice kind="error">
            <ul className="list-disc pl-5">{errors.map((er, i) => <li key={i}>{er}</li>)}</ul>
          </Notice>
        </div>
      )}

      <form onSubmit={save} className="space-y-6">
        <div className="card grid gap-5 sm:grid-cols-2">
          {includeLanguage && (
            <Field label="Active language" htmlFor="active_language" hint="Single-language enrichment (default de_CH).">
              <select id="active_language" value={language} onChange={(e) => setLanguage(e.target.value)} className="input">
                {["de_CH", "de", "en", "fr", "it"].map((l) => <option key={l} value={l}>{l}</option>)}
              </select>
            </Field>
          )}
          {numericFields.map((f) => (
            <Field key={f.key} label={f.label} htmlFor={f.key} hint={f.hint} info={f.info}>
              <input
                id={f.key}
                name={f.key}
                type="number"
                step={f.step ?? "1"}
                min="0"
                defaultValue={String(settings![f.key] ?? "")}
                className="input"
              />
            </Field>
          ))}
        </div>

        {jsonFields.length > 0 && (
          <div className="card space-y-4">
            <h2 className="font-semibold text-slate-900">Advanced (JSON)</h2>
            {jsonFields.map((f) => (
              <Field key={f.key} label={f.label} htmlFor={f.key} hint={f.hint} info={f.info}>
                <textarea
                  id={f.key}
                  name={f.key}
                  rows={f.rows ?? 3}
                  defaultValue={JSON.stringify(settings![f.key] ?? {}, null, 2)}
                  className="input font-mono text-xs"
                />
              </Field>
            ))}
          </div>
        )}

        <button type="submit" className="btn-primary" disabled={busy}>
          {busy ? "Saving…" : "Save settings"}
        </button>
      </form>
    </>
  );
}
