// =================================================================
// ui-forms.jsx — Advanced form primitives.
//
//   - Textarea:      auto-grow optional, full theming
//   - Select:        custom dropdown styled to match Input
//   - NativeSelect:  fallback wrapping native <select>
//   - Checkbox:      custom-styled checkbox + label
//   - RadioGroup:    radio group with vertical/horizontal layout
//   - Slider:        range input with value bubble
//   - NumberStepper: +/- buttons around a number input
//   - InputGroup:    horizontally-grouped controls (e.g. unit suffix)
//   - FieldRow:      horizontal label + control alignment (settings forms)
//   - FieldGroup:    multi-column field layout (1, 2, 3 cols)
//   - FormSection:   titled section with optional description
//   - InlineHelp:    icon + small text for hint or error
// =================================================================

// ---------- Textarea ----------
const Textarea = ({ value, onChange, rows = 4, autoGrow, placeholder, style, ...rest }) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!autoGrow || !ref.current) return;
    ref.current.style.height = "auto";
    ref.current.style.height = ref.current.scrollHeight + "px";
  }, [value, autoGrow]);
  return (
    <>
      <textarea ref={ref} className="hx-ta" rows={rows} value={value} onChange={onChange} placeholder={placeholder} style={style} {...rest}/>
      <style>{`
        .hx-ta {
          width: 100%; font: inherit; font-size: 13.5px;
          padding: 10px 12px;
          border: 1px solid var(--line); border-radius: 8px;
          resize: vertical; background: var(--panel); color: var(--ink);
          line-height: 1.5; min-height: 56px;
          transition: border-color .12s, box-shadow .12s;
        }
        .hx-ta:focus {
          outline: none; border-color: var(--accent);
          box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 18%, transparent);
        }
        .hx-ta::placeholder { color: var(--muted-2); }
      `}</style>
    </>
  );
};

// ---------- Select (custom dropdown) ----------
const Select = ({ value, onChange, options, placeholder = "Select…", disabled, prefix, style }) => {
  const [open, setOpen] = React.useState(false);
  const [activeIdx, setActiveIdx] = React.useState(0);
  const ref = React.useRef(null);
  const norm = options.map(o => typeof o === "object" ? o : { label: o, value: o });
  const selected = norm.find(o => o.value === value);

  React.useEffect(() => {
    if (!open) return;
    setActiveIdx(Math.max(0, norm.findIndex(o => o.value === value)));
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("click", onDoc);
    return () => document.removeEventListener("click", onDoc);
  }, [open]);

  const onKey = (e) => {
    if (e.key === "ArrowDown") { e.preventDefault(); setOpen(true); setActiveIdx(i => Math.min(norm.length - 1, i + 1)); }
    if (e.key === "ArrowUp")   { e.preventDefault(); setOpen(true); setActiveIdx(i => Math.max(0, i - 1)); }
    if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      if (open) { onChange(norm[activeIdx].value); setOpen(false); }
      else setOpen(true);
    }
    if (e.key === "Escape") setOpen(false);
  };

  return (
    <div ref={ref} className={`hx-sel ${open ? "open" : ""} ${disabled ? "disabled" : ""}`} style={style}>
      <button type="button" className="hx-sel-trigger"
              disabled={disabled}
              onClick={() => setOpen(o => !o)}
              onKeyDown={onKey}
              aria-haspopup="listbox" aria-expanded={open}>
        {prefix && <span className="hx-sel-prefix">{prefix}</span>}
        <span className={`hx-sel-val ${!selected ? "is-placeholder" : ""}`}>
          {selected ? selected.label : placeholder}
        </span>
        <IconChevD size={14}/>
      </button>
      {open && (
        <div className="hx-sel-menu" role="listbox">
          {norm.map((o, i) => (
            <button key={o.value} type="button" role="option"
                    aria-selected={o.value === value}
                    className={`hx-sel-opt ${o.value === value ? "selected" : ""} ${i === activeIdx ? "active" : ""}`}
                    onMouseEnter={() => setActiveIdx(i)}
                    onClick={() => { onChange(o.value); setOpen(false); }}>
              <span>{o.label}</span>
              {o.value === value && <IconCheck size={14} style={{ color: "var(--accent)" }}/>}
            </button>
          ))}
        </div>
      )}
      <style>{`
        .hx-sel { position: relative; display: inline-flex; width: 100%; }
        .hx-sel-trigger {
          display: flex; align-items: center; gap: 8px;
          width: 100%; height: var(--row);
          padding: 0 10px 0 12px;
          background: var(--panel); border: 1px solid var(--line);
          border-radius: 8px; font: inherit; font-size: 13.5px;
          color: var(--ink); text-align: left; cursor: pointer;
          transition: border-color .12s, box-shadow .12s;
        }
        .hx-sel-trigger:hover { border-color: color-mix(in oklab, var(--ink) 20%, var(--line)); }
        .hx-sel.open .hx-sel-trigger,
        .hx-sel-trigger:focus-visible {
          outline: none; border-color: var(--accent);
          box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 18%, transparent);
        }
        .hx-sel.disabled .hx-sel-trigger { opacity: .55; cursor: not-allowed; }
        .hx-sel-prefix { color: var(--muted); display: inline-flex; }
        .hx-sel-val { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .hx-sel-val.is-placeholder { color: var(--muted-2); }
        .hx-sel-menu {
          position: absolute; top: calc(100% + 4px); left: 0; right: 0;
          background: var(--panel); border: 1px solid var(--line);
          border-radius: 10px; box-shadow: var(--shadow-modal);
          padding: 4px; z-index: 40;
          max-height: 280px; overflow-y: auto;
          animation: hxpop .1s ease both;
        }
        .hx-sel-opt {
          display: flex; align-items: center; justify-content: space-between;
          width: 100%; padding: 8px 10px; border-radius: 6px;
          background: transparent; border: none; cursor: pointer;
          font: inherit; font-size: 13.5px; color: var(--ink-2); text-align: left;
        }
        .hx-sel-opt.active { background: var(--hover); color: var(--ink); }
        .hx-sel-opt.selected { color: var(--accent); font-weight: 500; }
      `}</style>
    </div>
  );
};

// ---------- Checkbox ----------
const Checkbox = ({ checked, onChange, label, description, disabled }) => (
  <label className={`hx-cb ${disabled ? "disabled" : ""}`}>
    <span className={`hx-cb-box ${checked ? "on" : ""}`}>
      {checked && <IconCheck size={11}/>}
    </span>
    <input type="checkbox" checked={checked} disabled={disabled}
           onChange={(e) => onChange(e.target.checked)}
           style={{ position: "absolute", opacity: 0, pointerEvents: "none" }}/>
    {(label || description) && (
      <span className="hx-cb-meta">
        {label && <span className="hx-cb-lbl">{label}</span>}
        {description && <span className="hx-cb-desc">{description}</span>}
      </span>
    )}
    <style>{`
      .hx-cb { display: inline-flex; align-items: flex-start; gap: 10px; cursor: pointer; user-select: none; }
      .hx-cb.disabled { opacity: .55; cursor: not-allowed; }
      .hx-cb-box {
        width: 18px; height: 18px; border-radius: 5px;
        border: 1.5px solid var(--line); background: var(--panel);
        display: inline-flex; align-items: center; justify-content: center;
        color: white; flex-shrink: 0; margin-top: 1px;
        transition: background .12s, border-color .12s, transform .04s;
      }
      .hx-cb:hover .hx-cb-box { border-color: color-mix(in oklab, var(--accent) 60%, var(--line)); }
      .hx-cb-box.on { background: var(--accent); border-color: var(--accent); }
      .hx-cb:active .hx-cb-box { transform: scale(.94); }
      .hx-cb-meta { display: flex; flex-direction: column; gap: 2px; }
      .hx-cb-lbl { font-size: 13.5px; color: var(--ink-2); line-height: 1.4; }
      .hx-cb-desc { font-size: 12.5px; color: var(--muted); line-height: 1.4; }
    `}</style>
  </label>
);

// ---------- RadioGroup ----------
const RadioGroup = ({ value, onChange, options, layout = "vertical", name }) => {
  const norm = options.map(o => typeof o === "object" ? o : { label: o, value: o });
  return (
    <div className={`hx-rg hx-rg-${layout}`} role="radiogroup">
      {norm.map(o => {
        const sel = value === o.value;
        return (
          <label key={o.value} className={`hx-radio ${sel ? "on" : ""} ${o.disabled ? "disabled" : ""}`}>
            <input type="radio" name={name} checked={sel} disabled={o.disabled}
                   onChange={() => onChange(o.value)}
                   style={{ position: "absolute", opacity: 0 }}/>
            <span className={`hx-radio-dot ${sel ? "on" : ""}`}><span/></span>
            <span className="hx-radio-meta">
              <span className="hx-radio-lbl">{o.label}</span>
              {o.description && <span className="hx-radio-desc">{o.description}</span>}
            </span>
          </label>
        );
      })}
      <style>{`
        .hx-rg { display: flex; gap: 10px; }
        .hx-rg-vertical { flex-direction: column; gap: 8px; }
        .hx-rg-horizontal { flex-wrap: wrap; }
        .hx-radio {
          display: flex; align-items: flex-start; gap: 10px;
          padding: 12px 14px; border: 1px solid var(--line); border-radius: 10px;
          cursor: pointer; background: var(--panel); flex: 1;
          transition: border-color .12s, background .12s;
        }
        .hx-radio:hover { background: var(--hover); }
        .hx-radio.on { border-color: var(--accent); background: var(--accent-soft); }
        .hx-radio.disabled { opacity: .55; cursor: not-allowed; }
        .hx-radio-dot {
          width: 18px; height: 18px; border-radius: 50%;
          border: 1.5px solid var(--line); background: var(--panel);
          display: inline-flex; align-items: center; justify-content: center;
          flex-shrink: 0; margin-top: 1px;
          transition: border-color .12s;
        }
        .hx-radio:hover .hx-radio-dot { border-color: color-mix(in oklab, var(--accent) 60%, var(--line)); }
        .hx-radio-dot.on { border-color: var(--accent); }
        .hx-radio-dot.on > span { width: 9px; height: 9px; border-radius: 50%; background: var(--accent); display: block; }
        .hx-radio-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
        .hx-radio-lbl { font-size: 13.5px; color: var(--ink); font-weight: 500; line-height: 1.4; white-space: nowrap; }
        .hx-radio-desc { font-size: 12.5px; color: var(--muted); line-height: 1.5; }
      `}</style>
    </div>
  );
};

// ---------- Slider ----------
const Slider = ({ value, onChange, min = 0, max = 100, step = 1, format, suffix, prefix }) => {
  const fmt = format || ((v) => v);
  const pct = ((value - min) / (max - min)) * 100;
  return (
    <div className="hx-slider">
      <div className="hx-slider-row">
        <input type="range" min={min} max={max} step={step} value={value}
               onChange={(e) => onChange(Number(e.target.value))}
               style={{ "--hx-slider-pct": pct + "%" }}/>
        <span className="hx-slider-val">{prefix}{fmt(value)}{suffix}</span>
      </div>
      <style>{`
        .hx-slider { width: 100%; }
        .hx-slider-row { display: flex; align-items: center; gap: 14px; }
        .hx-slider input[type=range] {
          flex: 1; -webkit-appearance: none; appearance: none;
          height: 6px; background: linear-gradient(to right,
            var(--accent) 0, var(--accent) var(--hx-slider-pct, 0%),
            var(--line-2) var(--hx-slider-pct, 0%), var(--line-2) 100%);
          border-radius: 999px; outline: none; cursor: pointer;
        }
        .hx-slider input[type=range]::-webkit-slider-thumb {
          -webkit-appearance: none; appearance: none;
          width: 18px; height: 18px; border-radius: 50%;
          background: var(--panel); border: 2px solid var(--accent);
          cursor: pointer; box-shadow: 0 1px 3px rgba(0,0,0,.18);
          transition: transform .12s;
        }
        .hx-slider input[type=range]::-webkit-slider-thumb:hover { transform: scale(1.12); }
        .hx-slider input[type=range]::-moz-range-thumb {
          width: 18px; height: 18px; border-radius: 50%;
          background: var(--panel); border: 2px solid var(--accent);
          cursor: pointer;
        }
        .hx-slider-val {
          font-family: var(--mono); font-size: 13px; font-feature-settings: "tnum";
          color: var(--ink); font-weight: 500; min-width: 48px; text-align: right;
        }
      `}</style>
    </div>
  );
};

// ---------- NumberStepper ----------
const NumberStepper = ({ value, onChange, min = 0, max = Infinity, step = 1, suffix }) => (
  <div className="hx-stepper">
    <button type="button" onClick={() => onChange(Math.max(min, value - step))} disabled={value <= min} aria-label="Decrement">−</button>
    <input type="number" value={value} min={min} max={max} step={step}
           onChange={(e) => {
             const n = Number(e.target.value);
             if (!isNaN(n)) onChange(Math.max(min, Math.min(max, n)));
           }}/>
    {suffix && <span className="hx-stepper-suffix">{suffix}</span>}
    <button type="button" onClick={() => onChange(Math.min(max, value + step))} disabled={value >= max} aria-label="Increment">+</button>
    <style>{`
      .hx-stepper {
        display: inline-flex; align-items: center;
        background: var(--panel); border: 1px solid var(--line);
        border-radius: 8px; overflow: hidden; height: var(--row);
      }
      .hx-stepper:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 18%, transparent); }
      .hx-stepper button {
        width: 32px; height: 100%;
        background: transparent; border: none; cursor: pointer;
        color: var(--ink-2); font-size: 16px; font-weight: 500;
        transition: background .12s;
      }
      .hx-stepper button:hover:not(:disabled) { background: var(--hover); color: var(--ink); }
      .hx-stepper button:disabled { opacity: .35; cursor: not-allowed; }
      .hx-stepper input {
        width: 56px; height: 100%; border: none; background: transparent;
        text-align: center; font: inherit; font-size: 13.5px;
        color: var(--ink); -moz-appearance: textfield;
        font-family: var(--mono); font-feature-settings: "tnum";
      }
      .hx-stepper input::-webkit-outer-spin-button,
      .hx-stepper input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
      .hx-stepper-suffix { color: var(--muted); font-size: 12.5px; padding-right: 4px; }
    `}</style>
  </div>
);

// ---------- FieldRow (horizontal label + control) ----------
// Use for settings-style forms where labels sit on the left.
const FieldRow = ({ label, hint, error, children, layout = "split" }) => (
  <div className={`hx-fr hx-fr-${layout}`}>
    <div className="hx-fr-label">
      <label>{label}</label>
      {hint && layout === "split" && <div className="hx-fr-hint">{hint}</div>}
    </div>
    <div className="hx-fr-ctrl">
      {children}
      {hint && layout !== "split" && <div className="hx-fr-hint hx-fr-hint-inline">{hint}</div>}
      {error && <div className="hx-fr-err">{error}</div>}
    </div>
    <style>{`
      .hx-fr { display: grid; gap: 16px; padding: 16px 0; border-bottom: 1px solid var(--line-2); }
      .hx-fr:last-child { border-bottom: none; }
      .hx-fr-split { grid-template-columns: minmax(180px, 1fr) minmax(0, 2fr); }
      .hx-fr-stacked { grid-template-columns: 1fr; gap: 8px; padding: 0; border: none; }
      .hx-fr-label > label { display: block; font-size: 13.5px; font-weight: 500; color: var(--ink); }
      .hx-fr-hint { font-size: 12.5px; color: var(--muted); margin-top: 4px; line-height: 1.5; max-width: 320px; }
      .hx-fr-hint-inline { max-width: none; }
      .hx-fr-err { font-size: 12.5px; color: var(--bad); margin-top: 4px; }
      @media (max-width: 720px) {
        .hx-fr-split { grid-template-columns: 1fr; }
      }
    `}</style>
  </div>
);

// ---------- FieldGroup (multi-column horizontal field layout) ----------
const FieldGroup = ({ cols = 2, children, gap = 14 }) => (
  <div className="hx-fg" style={{ gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`, gap }}>
    {children}
    <style>{`
      .hx-fg { display: grid; }
      .hx-fg > .hx-ff { margin-bottom: 0; }
      @media (max-width: 640px) {
        .hx-fg { grid-template-columns: 1fr !important; }
      }
    `}</style>
  </div>
);

// ---------- FormSection (titled block) ----------
const FormSection = ({ title, description, action, children }) => (
  <section className="hx-fs">
    {(title || description || action) && (
      <header className="hx-fs-head">
        <div>
          {title && <h3 className="hx-fs-title">{title}</h3>}
          {description && <p className="hx-fs-desc">{description}</p>}
        </div>
        {action}
      </header>
    )}
    <div className="hx-fs-body">{children}</div>
    <style>{`
      .hx-fs { display: flex; flex-direction: column; }
      .hx-fs-head {
        display: flex; justify-content: space-between; align-items: flex-start; gap: 16px;
        padding-bottom: 14px; border-bottom: 1px solid var(--line-2); margin-bottom: 10px;
      }
      .hx-fs-title { margin: 0; font-size: 14.5px; font-weight: 600; letter-spacing: -.005em; color: var(--ink); }
      .hx-fs-desc { margin: 4px 0 0; font-size: 13px; color: var(--muted); line-height: 1.55; max-width: 520px; }
      .hx-fs-body { display: flex; flex-direction: column; }
    `}</style>
  </section>
);

// ---------- InlineHelp ----------
const InlineHelp = ({ tone = "muted", children, icon }) => (
  <div className={`hx-ih hx-ih-${tone}`}>
    {icon && <span className="hx-ih-icon">{icon}</span>}
    <span>{children}</span>
    <style>{`
      .hx-ih { display: inline-flex; align-items: flex-start; gap: 6px; font-size: 12.5px; line-height: 1.5; }
      .hx-ih-muted { color: var(--muted); }
      .hx-ih-warn  { color: var(--warn); }
      .hx-ih-bad   { color: var(--bad); }
      .hx-ih-good  { color: var(--good); }
      .hx-ih-icon { display: inline-flex; flex-shrink: 0; margin-top: 1px; }
    `}</style>
  </div>
);

Object.assign(window, {
  Textarea, Select, Checkbox, RadioGroup, Slider, NumberStepper,
  FieldRow, FieldGroup, FormSection, InlineHelp,
});
