/* ============================================================
   F2 UI — Forms library
   Select · Checkbox · RadioGroup · Textarea · Slider · DatePicker · FileUpload
   Built on F2 tokens: hairline borders, amber focus ring, flat surfaces.
   ============================================================ */
(function () {
  const { Icon } = window.F2;
  const { injectCss, useDismiss } = window.SB;
  const RING = '0 0 0 3px rgba(229,154,60,0.18)';

  /* ---- shared field label ---- */
  function FieldLabel({ children, htmlFor, mono = true }) {
    if (!children) return null;
    return (
      <label htmlFor={htmlFor} style={{
        display: 'block', marginBottom: 6,
        fontFamily: mono ? 'var(--f2-font-mono)' : 'var(--f2-font-display)',
        fontSize: mono ? 11 : 13, fontWeight: 500,
        letterSpacing: mono ? '0.12em' : '0', textTransform: mono ? 'uppercase' : 'none',
        color: 'var(--f2-text-muted)',
      }}>{children}</label>
    );
  }

  /* ====================== Select ====================== */
  function Select({ value, onChange, options = [], placeholder = 'Select…', label, mono = true, disabled = false, error = false, id, style = {} }) {
    const [open, setOpen] = React.useState(false);
    const [active, setActive] = React.useState(0);
    const ref = React.useRef(null);
    const fieldId = id || (label ? `f2-sel-${label.replace(/\s+/g, '-').toLowerCase()}` : undefined);
    useDismiss(ref, () => setOpen(false), open);
    const opts = options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o));
    const current = opts.find((o) => o.value === value);
    const borderColor = error ? 'var(--f2-error)' : (open ? 'var(--f2-accent)' : 'var(--f2-border-strong)');

    function choose(o) { onChange && onChange(o.value); setOpen(false); }
    function onKey(e) {
      if (disabled) return;
      if (e.key === 'ArrowDown') { e.preventDefault(); if (!open) setOpen(true); else setActive((a) => Math.min(a + 1, opts.length - 1)); }
      else if (e.key === 'ArrowUp') { e.preventDefault(); setActive((a) => Math.max(a - 1, 0)); }
      else if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); if (open && opts[active]) choose(opts[active]); else setOpen(true); }
    }
    return (
      <div ref={ref} style={{ position: 'relative', ...style }}>
        <FieldLabel htmlFor={fieldId} mono={mono}>{label}</FieldLabel>
        <button id={fieldId} type="button" role="combobox" aria-expanded={open} aria-haspopup="listbox" disabled={disabled}
          onClick={() => !disabled && setOpen((o) => !o)} onKeyDown={onKey}
          style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, width: '100%',
            height: 42, padding: '0 12px 0 14px', background: 'var(--f2-input-bg)', cursor: disabled ? 'not-allowed' : 'pointer',
            border: `1px solid ${borderColor}`, borderRadius: 'var(--f2-radius-control)', color: current ? 'var(--f2-text)' : 'var(--f2-text-faint)',
            fontFamily: 'var(--f2-font-body)', fontSize: 15, opacity: disabled ? 0.5 : 1,
            boxShadow: open ? RING : 'none', transition: 'border-color var(--f2-dur-fast) var(--f2-ease), box-shadow var(--f2-dur-fast) var(--f2-ease)',
          }}>
          <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{current ? current.label : placeholder}</span>
          <Icon name="ChevronsUpDown" size={15} color="var(--f2-text-muted)" />
        </button>
        {open && (
          <ul role="listbox" style={{
            position: 'absolute', top: 'calc(100% + 6px)', left: 0, right: 0, zIndex: 40, margin: 0, padding: 5, listStyle: 'none',
            background: 'var(--f2-surface-card)', border: '1px solid var(--f2-border-strong)', borderRadius: 'var(--f2-radius-control)',
            boxShadow: 'var(--f2-elevation-overlay)', maxHeight: 240, overflowY: 'auto',
          }}>
            {opts.map((o, i) => {
              const sel = o.value === value;
              return (
                <li key={o.value} role="option" aria-selected={sel} onMouseEnter={() => setActive(i)} onClick={() => choose(o)}
                  style={{
                    display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, padding: '9px 10px', cursor: 'pointer',
                    borderRadius: 7, background: i === active ? 'var(--f2-surface-raised)' : 'transparent',
                    color: sel ? 'var(--f2-text)' : 'var(--f2-text-secondary)', fontSize: 14.5,
                  }}>
                  <span>{o.label}</span>
                  {sel && <Icon name="Check" size={15} color="var(--f2-accent-text)" />}
                </li>
              );
            })}
          </ul>
        )}
      </div>
    );
  }

  /* ====================== Checkbox ====================== */
  function Checkbox({ checked = false, onChange, label, disabled = false, indeterminate = false, error = false, id, style = {} }) {
    const ref = React.useRef(null);
    React.useEffect(() => { if (ref.current) ref.current.indeterminate = indeterminate && !checked; }, [indeterminate, checked]);
    const on = checked || indeterminate;
    return (
      <label style={{ display: 'inline-flex', alignItems: 'center', gap: 10, cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.5 : 1, ...style }}>
        <span style={{ position: 'relative', display: 'inline-flex', width: 20, height: 20, flex: '0 0 auto' }}>
          <input ref={ref} type="checkbox" checked={checked} disabled={disabled} id={id}
            onChange={(e) => onChange && onChange(e.target.checked)}
            style={{ position: 'absolute', inset: 0, margin: 0, opacity: 0, cursor: 'inherit' }} />
          <span aria-hidden="true" style={{
            width: 20, height: 20, borderRadius: 6, display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            background: on ? 'var(--f2-accent)' : 'var(--f2-input-bg)',
            border: `1px solid ${error ? 'var(--f2-error)' : (on ? 'var(--f2-accent)' : 'var(--f2-border-strong)')}`,
            color: 'var(--f2-text-on-accent)', transition: 'background var(--f2-dur-fast) var(--f2-ease), border-color var(--f2-dur-fast) var(--f2-ease)',
          }}>
            {checked && <Icon name="Check" size={14} stroke={2.4} />}
            {!checked && indeterminate && <Icon name="Minus" size={14} stroke={2.4} />}
          </span>
        </span>
        {label && <span style={{ fontSize: 15, color: 'var(--f2-text)', lineHeight: 1.4 }}>{label}</span>}
      </label>
    );
  }

  /* ====================== RadioGroup ====================== */
  function RadioGroup({ value, onChange, options = [], name, label, orientation = 'vertical', disabled = false, style = {} }) {
    const grpName = name || `f2-radio-${Math.random().toString(36).slice(2, 7)}`;
    const opts = options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o));
    return (
      <div role="radiogroup" aria-label={label} style={style}>
        <FieldLabel>{label}</FieldLabel>
        <div style={{ display: 'flex', flexDirection: orientation === 'horizontal' ? 'row' : 'column', gap: orientation === 'horizontal' ? 20 : 12, flexWrap: 'wrap' }}>
          {opts.map((o) => {
            const sel = o.value === value;
            const dis = disabled || o.disabled;
            return (
              <label key={o.value} style={{ display: 'inline-flex', alignItems: 'flex-start', gap: 10, cursor: dis ? 'not-allowed' : 'pointer', opacity: dis ? 0.5 : 1 }}>
                <span style={{ position: 'relative', display: 'inline-flex', width: 20, height: 20, flex: '0 0 auto', marginTop: 1 }}>
                  <input type="radio" name={grpName} checked={sel} disabled={dis} onChange={() => onChange && onChange(o.value)}
                    style={{ position: 'absolute', inset: 0, margin: 0, opacity: 0, cursor: 'inherit' }} />
                  <span aria-hidden="true" style={{
                    width: 20, height: 20, borderRadius: '50%', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                    background: 'var(--f2-input-bg)', border: `1px solid ${sel ? 'var(--f2-accent)' : 'var(--f2-border-strong)'}`,
                    transition: 'border-color var(--f2-dur-fast) var(--f2-ease)',
                  }}>
                    {sel && <span style={{ width: 9, height: 9, borderRadius: '50%', background: 'var(--f2-accent)' }} />}
                  </span>
                </span>
                <span style={{ display: 'flex', flexDirection: 'column' }}>
                  <span style={{ fontSize: 15, color: 'var(--f2-text)', lineHeight: 1.4 }}>{o.label}</span>
                  {o.hint && <span style={{ fontSize: 13, color: 'var(--f2-text-muted)', marginTop: 2 }}>{o.hint}</span>}
                </span>
              </label>
            );
          })}
        </div>
      </div>
    );
  }

  /* ====================== Textarea ====================== */
  function Textarea({ label, mono = true, value, onChange, placeholder, rows = 4, maxLength, error = false, disabled = false, id, style = {} }) {
    const [focus, setFocus] = React.useState(false);
    const fieldId = id || (label ? `f2-ta-${label.replace(/\s+/g, '-').toLowerCase()}` : undefined);
    const len = (value || '').length;
    return (
      <div style={{ ...style }}>
        <FieldLabel htmlFor={fieldId} mono={mono}>{label}</FieldLabel>
        <div style={{
          border: `1px solid ${error ? 'var(--f2-error)' : (focus ? 'var(--f2-accent)' : 'var(--f2-border-strong)')}`,
          borderRadius: 'var(--f2-radius-control)', background: 'var(--f2-input-bg)', boxShadow: focus ? RING : 'none',
          transition: 'border-color var(--f2-dur-fast) var(--f2-ease), box-shadow var(--f2-dur-fast) var(--f2-ease)',
        }}>
          <textarea id={fieldId} rows={rows} placeholder={placeholder} value={value} disabled={disabled} maxLength={maxLength}
            onChange={(e) => onChange && onChange(e.target.value)} onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
            style={{
              display: 'block', width: '100%', border: 'none', outline: 'none', background: 'transparent', resize: 'vertical',
              padding: '11px 14px', color: 'var(--f2-text)', fontFamily: 'var(--f2-font-body)', fontSize: 15, lineHeight: 1.55,
              opacity: disabled ? 0.5 : 1,
            }} />
          {maxLength != null && (
            <div style={{ textAlign: 'right', padding: '0 12px 8px', fontFamily: 'var(--f2-font-mono)', fontSize: 11, color: len >= maxLength ? 'var(--f2-warning)' : 'var(--f2-text-faint)' }}>{len} / {maxLength}</div>
          )}
        </div>
      </div>
    );
  }

  /* ====================== Slider ====================== */
  injectCss('f2-range-css', `
    .f2-range{ -webkit-appearance:none; appearance:none; width:100%; height:22px; background:transparent; cursor:pointer; }
    .f2-range:disabled{ cursor:not-allowed; opacity:.5; }
    .f2-range::-webkit-slider-runnable-track{ height:4px; border-radius:999px; background:var(--track); }
    .f2-range::-moz-range-track{ height:4px; border-radius:999px; background:var(--f2-surface-sunken); }
    .f2-range::-moz-range-progress{ height:4px; border-radius:999px; background:var(--f2-accent); }
    .f2-range::-webkit-slider-thumb{ -webkit-appearance:none; appearance:none; margin-top:-7px; width:18px; height:18px; border-radius:50%;
      background:var(--f2-text); border:3px solid var(--f2-accent); box-sizing:border-box; transition:transform var(--f2-dur-fast) var(--f2-ease); }
    .f2-range::-moz-range-thumb{ width:18px; height:18px; border-radius:50%; background:var(--f2-text); border:3px solid var(--f2-accent); box-sizing:border-box; }
    .f2-range:active::-webkit-slider-thumb{ transform:scale(1.12); }
    .f2-range:focus-visible::-webkit-slider-thumb{ box-shadow:0 0 0 4px rgba(229,154,60,0.22); }
  `);
  function Slider({ value = 50, min = 0, max = 100, step = 1, onChange, label, unit = '', disabled = false, showValue = true, id, style = {} }) {
    const pct = Math.max(0, Math.min(100, ((value - min) / (max - min)) * 100));
    const fieldId = id || (label ? `f2-rng-${label.replace(/\s+/g, '-').toLowerCase()}` : undefined);
    return (
      <div style={{ ...style }}>
        {(label || showValue) && (
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
            <FieldLabel htmlFor={fieldId}>{label}</FieldLabel>
            {showValue && <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 13, color: 'var(--f2-text)' }}>{value}{unit}</span>}
          </div>
        )}
        <input id={fieldId} className="f2-range" type="range" min={min} max={max} step={step} value={value} disabled={disabled}
          aria-label={label} onChange={(e) => onChange && onChange(Number(e.target.value))}
          style={{ '--track': `linear-gradient(90deg, var(--f2-accent) ${pct}%, var(--f2-surface-sunken) ${pct}%)` }} />
      </div>
    );
  }

  /* ====================== DatePicker ====================== */
  const MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
  const DOW = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'];
  function ymd(d) { return d ? `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` : ''; }
  function sameDay(a, b) { return a && b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }
  function DatePicker({ value, onChange, label, placeholder = 'Pick a date', disabled = false, id, style = {} }) {
    const sel = value ? new Date(value) : null;
    const [open, setOpen] = React.useState(false);
    const [view, setView] = React.useState(() => (sel ? new Date(sel.getFullYear(), sel.getMonth(), 1) : new Date()));
    const ref = React.useRef(null);
    const fieldId = id || (label ? `f2-date-${label.replace(/\s+/g, '-').toLowerCase()}` : undefined);
    useDismiss(ref, () => setOpen(false), open);
    const today = new Date();
    const first = new Date(view.getFullYear(), view.getMonth(), 1);
    const startPad = (first.getDay() + 6) % 7; // Monday-first
    const daysInMonth = new Date(view.getFullYear(), view.getMonth() + 1, 0).getDate();
    const cells = [];
    for (let i = 0; i < startPad; i++) cells.push(null);
    for (let d = 1; d <= daysInMonth; d++) cells.push(new Date(view.getFullYear(), view.getMonth(), d));

    return (
      <div ref={ref} style={{ position: 'relative', ...style }}>
        <FieldLabel htmlFor={fieldId}>{label}</FieldLabel>
        <button id={fieldId} type="button" disabled={disabled} onClick={() => !disabled && setOpen((o) => !o)}
          style={{
            display: 'flex', alignItems: 'center', gap: 10, width: '100%', height: 42, padding: '0 14px', cursor: disabled ? 'not-allowed' : 'pointer',
            background: 'var(--f2-input-bg)', border: `1px solid ${open ? 'var(--f2-accent)' : 'var(--f2-border-strong)'}`,
            borderRadius: 'var(--f2-radius-control)', color: sel ? 'var(--f2-text)' : 'var(--f2-text-faint)', fontFamily: 'var(--f2-font-body)', fontSize: 15,
            boxShadow: open ? RING : 'none', opacity: disabled ? 0.5 : 1,
          }}>
          <Icon name="Calendar" size={16} color="var(--f2-text-muted)" />
          <span>{sel ? sel.toLocaleDateString('en-US', { day: 'numeric', month: 'short', year: 'numeric' }) : placeholder}</span>
        </button>
        {open && (
          <div role="dialog" style={{
            position: 'absolute', top: 'calc(100% + 6px)', left: 0, zIndex: 40, width: 280, padding: 14,
            background: 'var(--f2-surface-card)', border: '1px solid var(--f2-border-strong)', borderRadius: 'var(--f2-radius-md)', boxShadow: 'var(--f2-elevation-overlay)',
          }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
              <button type="button" aria-label="Previous month" onClick={() => setView(new Date(view.getFullYear(), view.getMonth() - 1, 1))} style={navBtn}><Icon name="ChevronLeft" size={16} /></button>
              <span style={{ fontFamily: 'var(--f2-font-display)', fontWeight: 600, fontSize: 14.5, color: 'var(--f2-text)' }}>{MONTHS[view.getMonth()]} {view.getFullYear()}</span>
              <button type="button" aria-label="Next month" onClick={() => setView(new Date(view.getFullYear(), view.getMonth() + 1, 1))} style={navBtn}><Icon name="ChevronRight" size={16} /></button>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 2, marginBottom: 4 }}>
              {DOW.map((d) => <div key={d} style={{ textAlign: 'center', fontFamily: 'var(--f2-font-mono)', fontSize: 10, letterSpacing: '0.08em', color: 'var(--f2-text-faint)', padding: '2px 0' }}>{d}</div>)}
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 2 }}>
              {cells.map((d, i) => {
                if (!d) return <span key={i} />;
                const isSel = sameDay(d, sel); const isToday = sameDay(d, today);
                return (
                  <button key={i} type="button" onClick={() => { onChange && onChange(ymd(d)); setOpen(false); }}
                    style={{
                      height: 32, borderRadius: 7, border: isToday && !isSel ? '1px solid var(--f2-border-strong)' : '1px solid transparent', cursor: 'pointer',
                      background: isSel ? 'var(--f2-accent)' : 'transparent', color: isSel ? 'var(--f2-text-on-accent)' : 'var(--f2-text-secondary)',
                      fontFamily: 'var(--f2-font-body)', fontSize: 13.5, transition: 'background var(--f2-dur-fast) var(--f2-ease)',
                    }}
                    onMouseEnter={(e) => { if (!isSel) e.currentTarget.style.background = 'var(--f2-surface-raised)'; }}
                    onMouseLeave={(e) => { if (!isSel) e.currentTarget.style.background = 'transparent'; }}>
                    {d.getDate()}
                  </button>
                );
              })}
            </div>
          </div>
        )}
      </div>
    );
  }
  const navBtn = { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 28, height: 28, borderRadius: 7, border: '1px solid var(--f2-border)', background: 'var(--f2-surface-raised)', color: 'var(--f2-text-secondary)', cursor: 'pointer' };

  /* ====================== FileUpload ====================== */
  function FileUpload({ onFiles, accept, multiple = false, label, hint = 'PNG, PDF or CSV up to 10MB', disabled = false, style = {} }) {
    const [over, setOver] = React.useState(false);
    const [files, setFiles] = React.useState([]);
    const inputRef = React.useRef(null);
    function take(list) { const arr = Array.from(list || []); setFiles(multiple ? arr : arr.slice(0, 1)); onFiles && onFiles(arr); }
    function remove(i) { const next = files.filter((_, x) => x !== i); setFiles(next); onFiles && onFiles(next); }
    return (
      <div style={{ ...style }}>
        <FieldLabel>{label}</FieldLabel>
        <div role="button" tabIndex={disabled ? -1 : 0} aria-label={label || 'Upload files'}
          onClick={() => !disabled && inputRef.current && inputRef.current.click()}
          onKeyDown={(e) => { if ((e.key === 'Enter' || e.key === ' ') && !disabled) { e.preventDefault(); inputRef.current.click(); } }}
          onDragOver={(e) => { e.preventDefault(); if (!disabled) setOver(true); }}
          onDragLeave={() => setOver(false)}
          onDrop={(e) => { e.preventDefault(); setOver(false); if (!disabled) take(e.dataTransfer.files); }}
          style={{
            display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 10, padding: '28px 20px', textAlign: 'center',
            border: `1.5px dashed ${over ? 'var(--f2-accent)' : 'var(--f2-border-strong)'}`, borderRadius: 'var(--f2-radius-md)',
            background: over ? 'var(--f2-surface-accent)' : 'var(--f2-surface-raised)', cursor: disabled ? 'not-allowed' : 'pointer',
            opacity: disabled ? 0.5 : 1, transition: 'border-color var(--f2-dur-fast) var(--f2-ease), background var(--f2-dur-fast) var(--f2-ease)',
          }}>
          <span style={{ color: over ? 'var(--f2-accent-text)' : 'var(--f2-text-muted)' }}><Icon name="UploadCloud" size={26} stroke={1.5} /></span>
          <div style={{ fontSize: 15, color: 'var(--f2-text)' }}><span style={{ color: 'var(--f2-accent-text)', fontWeight: 500 }}>Click to upload</span> or drag and drop</div>
          <div style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 11, letterSpacing: '0.04em', color: 'var(--f2-text-faint)' }}>{hint}</div>
          <input ref={inputRef} type="file" accept={accept} multiple={multiple} style={{ display: 'none' }} onChange={(e) => take(e.target.files)} />
        </div>
        {files.length > 0 && (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 12 }}>
            {files.map((f, i) => (
              <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 12px', border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-control)', background: 'var(--f2-surface-card)' }}>
                <Icon name="FileText" size={16} color="var(--f2-text-muted)" />
                <span style={{ flex: 1, fontSize: 14, color: 'var(--f2-text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{f.name}</span>
                <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 11, color: 'var(--f2-text-faint)' }}>{(f.size / 1024).toFixed(0)} KB</span>
                <button type="button" aria-label={`Remove ${f.name}`} onClick={(e) => { e.stopPropagation(); remove(i); }} style={{ display: 'inline-flex', background: 'none', border: 'none', color: 'var(--f2-text-muted)', cursor: 'pointer' }}><Icon name="X" size={15} /></button>
              </div>
            ))}
          </div>
        )}
      </div>
    );
  }

  Object.assign(window.F2, { FieldLabel, Select, Checkbox, RadioGroup, Textarea, Slider, DatePicker, FileUpload });
})();
