// Lotus Assist — Form Field Library
// The reusable primitives. Every form = JSON + <FormRenderer schema={...} />.
// Each field is a controlled component. Validation is schema-driven.

const { useState, useId } = React;

// ─── Shared input atoms ──────────────────────────────────────
const baseInput = {
  width: "100%",
  padding: "14px 16px",
  borderRadius: 12,
  border: "1.5px solid var(--border)",
  fontSize: 16,
  fontFamily: "inherit",
  color: "var(--fg)",
  background: "#fff",
  boxSizing: "border-box",
  transition: "border-color 160ms var(--ease-out), box-shadow 160ms var(--ease-out)",
  outline: "none",
};

function FieldShell({ label, required, help, error, children, id }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      {label && (
        <label htmlFor={id} style={{
          fontSize: 15, fontWeight: 600, color: "var(--la-teal-900)",
          display: "flex", alignItems: "baseline", gap: 6,
        }}>
          <span>{label}</span>
          {required && <span style={{ color: "var(--accent)", fontSize: 13, fontWeight: 600 }}>required</span>}
        </label>
      )}
      {help && <div style={{ fontSize: 13.5, color: "var(--fg-soft)", lineHeight: 1.5, marginBottom: 2 }}>{help}</div>}
      {children}
      {error && <div style={{ fontSize: 13, color: "var(--la-magenta-700)", marginTop: 2 }}>⚠ {error}</div>}
    </div>
  );
}

// ─── Text / Email / Tel ──────────────────────────────────────
function TextField({ field, value, onChange, error }) {
  const id = useId();
  const [focus, setFocus] = useState(false);
  const isTel = field.type === "tel";
  // AU phone formatter: strips non-digits; accepts 04xx xxx xxx or (0x) xxxx xxxx patterns.
  const formatAuPhone = (raw) => {
    const d = raw.replace(/[^\d+]/g, "").replace(/\+61/, "0");
    if (d.startsWith("04") && d.length >= 5) {
      return d.slice(0, 4) + (d.length > 4 ? " " + d.slice(4, 7) : "") + (d.length > 7 ? " " + d.slice(7, 10) : "");
    }
    if (d.startsWith("0") && d.length >= 3) {
      return "(" + d.slice(0, 2) + ")" + (d.length > 2 ? " " + d.slice(2, 6) : "") + (d.length > 6 ? " " + d.slice(6, 10) : "");
    }
    return d;
  };
  return (
    <FieldShell id={id} label={field.label} required={field.required} help={field.help} error={error}>
      <div style={{ position: "relative" }}>
        {isTel && (
          <span style={{
            position: "absolute", left: 14, top: "50%", transform: "translateY(-50%)",
            fontSize: 15, color: "var(--fg-soft)", fontWeight: 500, pointerEvents: "none",
            display: "inline-flex", alignItems: "center", gap: 6,
          }}>
            <span aria-hidden="true" style={{ fontSize: 13 }}>🇦🇺</span>
            <span>+61</span>
            <span style={{ width: 1, height: 18, background: "var(--border)" }} />
          </span>
        )}
        <input
          id={id}
          type={field.type === "email" ? "email" : isTel ? "tel" : "text"}
          inputMode={isTel ? "tel" : undefined}
          autoComplete={isTel ? "tel-national" : field.type === "email" ? "email" : undefined}
          value={value || ""}
          onChange={(e) => onChange(isTel ? formatAuPhone(e.target.value) : e.target.value)}
          placeholder={field.placeholder || (isTel ? "04xx xxx xxx" : undefined)}
          required={field.required}
          onFocus={() => setFocus(true)}
          onBlur={() => setFocus(false)}
          style={{
            ...baseInput,
            paddingLeft: isTel ? 84 : baseInput.padding.split(" ")[1],
            borderColor: error ? "var(--la-magenta-600)" : focus ? "var(--brand)" : baseInput.border,
            boxShadow: focus ? "0 0 0 4px var(--focus-ring)" : "none",
          }}
        />
      </div>
    </FieldShell>
  );
}

// ─── Textarea ────────────────────────────────────────────────
function TextareaField({ field, value, onChange, error }) {
  const id = useId();
  const [focus, setFocus] = useState(false);
  return (
    <FieldShell id={id} label={field.label} required={field.required} help={field.help} error={error}>
      <textarea
        id={id}
        value={value || ""}
        onChange={(e) => onChange(e.target.value)}
        placeholder={field.placeholder}
        required={field.required}
        rows={field.rows || 4}
        onFocus={() => setFocus(true)}
        onBlur={() => setFocus(false)}
        style={{
          ...baseInput,
          resize: "vertical",
          minHeight: 100,
          lineHeight: 1.5,
          borderColor: error ? "var(--la-magenta-600)" : focus ? "var(--brand)" : baseInput.border,
          boxShadow: focus ? "0 0 0 4px var(--focus-ring)" : "none",
        }}
      />
    </FieldShell>
  );
}

// ─── Rating (1-10 scale like Zapier NPS) ─────────────────────
function RatingField({ field, value, onChange, error }) {
  const id = useId();
  const max = field.max || 10;
  const min = field.min || 1;
  const items = Array.from({ length: max - min + 1 }, (_, i) => i + min);
  return (
    <FieldShell id={id} label={field.label} required={field.required} help={field.help} error={error}>
      <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
        {items.map((n) => {
          const active = value === n;
          // Color gradient from magenta (low) → gold (mid) → green (high)
          const pct = (n - min) / (max - min);
          const activeColor = pct < 0.34 ? "var(--la-magenta-600)" : pct < 0.67 ? "var(--la-gold-500)" : "var(--la-green-600)";
          return (
            <button
              key={n}
              type="button"
              onClick={() => onChange(n)}
              aria-pressed={active}
              style={{
                flex: "1 1 auto", minWidth: 44, height: 48,
                borderRadius: 12,
                border: `2px solid ${active ? activeColor : "var(--border)"}`,
                background: active ? activeColor : "#fff",
                color: active ? "#fff" : "var(--fg)",
                fontSize: 15, fontWeight: 600, cursor: "pointer",
                fontFamily: "inherit",
                transition: "all 160ms var(--ease-out)",
              }}
              onMouseOver={(e) => { if (!active) e.currentTarget.style.borderColor = "var(--brand)"; }}
              onMouseOut={(e) => { if (!active) e.currentTarget.style.borderColor = "var(--border)"; }}
            >{n}</button>
          );
        })}
      </div>
      {field.scaleLabels && (
        <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12.5, color: "var(--fg-muted)", marginTop: 6 }}>
          <span>{field.scaleLabels.low}</span>
          <span>{field.scaleLabels.high}</span>
        </div>
      )}
    </FieldShell>
  );
}

// ─── Radio group (Yes/No and n-option) ───────────────────────
function RadioField({ field, value, onChange, error }) {
  const id = useId();
  const options = field.options || [];
  const layout = field.layout || (options.length <= 3 ? "inline" : "stack");
  return (
    <FieldShell id={id} label={field.label} required={field.required} help={field.help} error={error}>
      <div style={{ display: layout === "inline" ? "flex" : "grid", gap: 10, flexWrap: "wrap", gridTemplateColumns: layout === "stack" ? "1fr" : undefined }}>
        {options.map((opt) => {
          const v = typeof opt === "string" ? opt : opt.value;
          const label = typeof opt === "string" ? opt : opt.label;
          const desc = typeof opt === "object" ? opt.description : null;
          const active = value === v;
          return (
            <button
              key={v}
              type="button"
              onClick={() => onChange(v)}
              aria-pressed={active}
              style={{
                flex: layout === "inline" ? "1 1 120px" : undefined,
                display: "flex", alignItems: "flex-start", gap: 12,
                padding: "14px 16px",
                borderRadius: 12,
                border: `2px solid ${active ? "var(--brand)" : "var(--border)"}`,
                background: active ? "var(--brand-soft)" : "#fff",
                color: "var(--fg)",
                cursor: "pointer",
                fontFamily: "inherit",
                textAlign: "left",
                transition: "all 160ms var(--ease-out)",
              }}
            >
              <span style={{
                width: 20, height: 20, borderRadius: 999, flexShrink: 0, marginTop: 2,
                border: `2px solid ${active ? "var(--brand)" : "var(--border-strong)"}`,
                background: "#fff",
                display: "inline-flex", alignItems: "center", justifyContent: "center",
              }}>
                {active && <span style={{ width: 10, height: 10, borderRadius: 999, background: "var(--brand)" }} />}
              </span>
              <span style={{ display: "flex", flexDirection: "column", gap: 2 }}>
                <span style={{ fontSize: 15, fontWeight: 600 }}>{label}</span>
                {desc && <span style={{ fontSize: 13, color: "var(--fg-soft)", lineHeight: 1.45, fontWeight: 400 }}>{desc}</span>}
              </span>
            </button>
          );
        })}
      </div>
    </FieldShell>
  );
}

// ─── Select (dropdown) ───────────────────────────────────────
function SelectField({ field, value, onChange, error }) {
  const id = useId();
  const [focus, setFocus] = useState(false);
  return (
    <FieldShell id={id} label={field.label} required={field.required} help={field.help} error={error}>
      <select
        id={id}
        value={value || ""}
        onChange={(e) => onChange(e.target.value)}
        required={field.required}
        onFocus={() => setFocus(true)}
        onBlur={() => setFocus(false)}
        style={{
          ...baseInput,
          appearance: "none",
          backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23003237' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>")`,
          backgroundRepeat: "no-repeat",
          backgroundPosition: "right 16px center",
          paddingRight: 44,
          borderColor: error ? "var(--la-magenta-600)" : focus ? "var(--brand)" : baseInput.border,
          boxShadow: focus ? "0 0 0 4px var(--focus-ring)" : "none",
        }}
      >
        <option value="" disabled>{field.placeholder || "Select…"}</option>
        {(field.options || []).map((opt) => {
          const v = typeof opt === "string" ? opt : opt.value;
          const label = typeof opt === "string" ? opt : opt.label;
          return <option key={v} value={v}>{label}</option>;
        })}
      </select>
    </FieldShell>
  );
}

// ─── Checkbox group (multi-select) ───────────────────────────
function CheckboxGroupField({ field, value, onChange, error }) {
  const id = useId();
  const values = Array.isArray(value) ? value : [];
  const toggle = (v) => {
    if (values.includes(v)) onChange(values.filter(x => x !== v));
    else onChange([...values, v]);
  };
  return (
    <FieldShell id={id} label={field.label} required={field.required} help={field.help} error={error}>
      <div style={{ display: "grid", gap: 8 }}>
        {(field.options || []).map((opt) => {
          const v = typeof opt === "string" ? opt : opt.value;
          const label = typeof opt === "string" ? opt : opt.label;
          const active = values.includes(v);
          return (
            <button
              key={v}
              type="button"
              onClick={() => toggle(v)}
              style={{
                display: "flex", alignItems: "center", gap: 12,
                padding: "12px 14px",
                borderRadius: 12,
                border: `2px solid ${active ? "var(--brand)" : "var(--border)"}`,
                background: active ? "var(--brand-soft)" : "#fff",
                cursor: "pointer", fontFamily: "inherit", textAlign: "left",
              }}
            >
              <span style={{
                width: 22, height: 22, borderRadius: 6,
                border: `2px solid ${active ? "var(--brand)" : "var(--border-strong)"}`,
                background: active ? "var(--brand)" : "#fff",
                display: "inline-flex", alignItems: "center", justifyContent: "center",
                flexShrink: 0,
              }}>
                {active && <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>}
              </span>
              <span style={{ fontSize: 15, fontWeight: 500 }}>{label}</span>
            </button>
          );
        })}
      </div>
    </FieldShell>
  );
}

// ─── Date ────────────────────────────────────────────────────
function DateField({ field, value, onChange, error }) {
  const id = useId();
  const [focus, setFocus] = useState(false);
  // Australian format hint (dd/mm/yyyy). The native date input renders per
  // the user's OS locale, but we explicitly use lang="en-AU" to nudge it.
  return (
    <FieldShell id={id} label={field.label} required={field.required} help={field.help || "Date format: dd/mm/yyyy"} error={error}>
      <input
        id={id}
        type="date"
        lang="en-AU"
        value={value || ""}
        onChange={(e) => onChange(e.target.value)}
        required={field.required}
        onFocus={() => setFocus(true)}
        onBlur={() => setFocus(false)}
        style={{
          ...baseInput,
          borderColor: error ? "var(--la-magenta-600)" : focus ? "var(--brand)" : baseInput.border,
          boxShadow: focus ? "0 0 0 4px var(--focus-ring)" : "none",
        }}
      />
    </FieldShell>
  );
}

// ─── Section heading (not a field, but declared in schema) ───
function SectionHeading({ field }) {
  return (
    <div style={{ margin: "8px 0 -4px", paddingTop: 8, borderTop: field.divider ? "1px solid var(--border)" : "0" }}>
      <h3 style={{ margin: "0 0 4px", fontSize: 20, fontWeight: 700, color: "var(--la-teal-900)" }}>{field.label}</h3>
      {field.help && <p style={{ margin: 0, color: "var(--fg-soft)", fontSize: 14.5, lineHeight: 1.55 }}>{field.help}</p>}
    </div>
  );
}

// ─── The dispatcher ──────────────────────────────────────────
function Field({ field, value, onChange, error }) {
  switch (field.type) {
    case "text":
    case "email":
    case "tel":
      return <TextField field={field} value={value} onChange={onChange} error={error} />;
    case "textarea":
      return <TextareaField field={field} value={value} onChange={onChange} error={error} />;
    case "rating":
      return <RatingField field={field} value={value} onChange={onChange} error={error} />;
    case "radio":
      return <RadioField field={field} value={value} onChange={onChange} error={error} />;
    case "select":
      return <SelectField field={field} value={value} onChange={onChange} error={error} />;
    case "checkbox":
      return <CheckboxGroupField field={field} value={value} onChange={onChange} error={error} />;
    case "date":
      return <DateField field={field} value={value} onChange={onChange} error={error} />;
    case "heading":
      return <SectionHeading field={field} />;
    default:
      return <div style={{ padding: 12, background: "#FFE", border: "1px dashed #CC0", borderRadius: 8, fontSize: 13 }}>Unknown field type: <code>{field.type}</code></div>;
  }
}

Object.assign(window, { Field, FieldShell });
