// ============================================================================
// IdChip + IdInput — inline validation atoms.
//
// <IdChip kind="iswc" value="T1010551172" />
//   Renders the value with a ✓/✕/△ status pill. Clicking the chip opens a
//   tiny popover explaining the rule, the parsed result, and (if the body is
//   right but the check digit is wrong) a one-click "Apply suggested fix"
//   that calls onApply(suggestion).
//
// <IdInput kind="upc" value=... onChange=... />
//   A standard input with a live red ring + tooltip on blur when invalid,
//   and an inline "Apply fix" affordance when one is available.
//
// EXPORT: window.IdChip, window.IdInput
// ============================================================================
(function () {
  const { useState, useMemo, useRef, useEffect } = React;

  function statusOf(r) {
    if (!r) return 'unknown';
    if (r.skipped) return 'empty';
    if (r.valid === true) return 'ok';
    if (r.valid === 'warn') return 'warn';
    return 'bad';
  }

  function StatusDot({ s }) {
    const map = {
      ok:   { bg: '#0a7d3b', fg: '#fff', t: '✓' },
      warn: { bg: '#b76f00', fg: '#fff', t: '△' },
      bad:  { bg: '#a3261b', fg: '#fff', t: '✕' },
      empty:{ bg: 'var(--bg-2)', fg: 'var(--ink-3)', t: '·' },
      unknown:{ bg:'var(--bg-2)', fg:'var(--ink-3)', t:'?' },
    };
    const m = map[s] || map.unknown;
    return (
      <span style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        width: 14, height: 14, fontSize: 10, lineHeight: 1, fontWeight: 700,
        background: m.bg, color: m.fg, borderRadius: 0 }}>{m.t}</span>);
  }

  function Popover({ rect, onClose, children }) {
    const ref = useRef(null);
    useEffect(() => {
      const onDown = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
      document.addEventListener('mousedown', onDown);
      return () => document.removeEventListener('mousedown', onDown);
    }, [onClose]);
    if (!rect) return null;
    const top = rect.bottom + 6;
    const left = Math.max(8, Math.min(window.innerWidth - 360, rect.left));
    return (
      <div ref={ref} style={{ position: 'fixed', top, left, zIndex: 200, width: 340,
        background: 'var(--bg)', border: '1px solid var(--rule)', boxShadow: '0 8px 30px rgba(0,0,0,0.25)',
        padding: 12 }}>{children}</div>);
  }

  function IdChip({ kind, value, onApply, compact }) {
    const [open, setOpen] = useState(false);
    const [rect, setRect] = useState(null);
    const r = useMemo(() => (window.IdCodes && value) ? window.IdCodes.validate(kind, value) : null, [kind, value]);
    const fmt = (window.IdCodes && window.IdCodes.formats[kind]) || { label: kind };
    const s = statusOf(r);
    if (!value) return null;

    const open2 = (e) => {
      const rr = e.currentTarget.getBoundingClientRect();
      setRect(rr); setOpen(true);
    };

    return (
      <>
        <button onClick={open2} className="ff-mono"
          title={fmt.label + (r && r.reason ? ' — ' + r.reason : '')}
          style={{ display: 'inline-flex', alignItems: 'center', gap: 6,
            padding: compact ? '1px 6px' : '2px 8px', fontSize: compact ? 10 : 11,
            border: '1px solid var(--rule)', background: 'transparent',
            color: s === 'bad' ? 'var(--err, #a3261b)' : 'var(--ink)',
            cursor: 'pointer' }}>
          <StatusDot s={s} />
          <span style={{ opacity: 0.6, textTransform: 'uppercase', letterSpacing: 0.5 }}>{fmt.label}</span>
          <span>{value}</span>
        </button>
        {open && (
          <Popover rect={rect} onClose={() => setOpen(false)}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
              <StatusDot s={s} />
              <strong style={{ fontSize: 12 }}>{fmt.label}</strong>
              <span className="ff-mono" style={{ fontSize: 11, color: 'var(--ink-3)', marginLeft: 'auto' }}>{value}</span>
            </div>
            <div style={{ fontSize: 11, color: 'var(--ink-2)', lineHeight: 1.4 }}>
              <div><strong>Pattern:</strong> {fmt.pattern}</div>
              <div><strong>Check:</strong> {fmt.body}</div>
              <div><strong>Used in:</strong> {fmt.scope}</div>
              {r && r.normalized && <div style={{ marginTop: 6 }}><strong>Canonical:</strong> <span className="ff-mono">{r.normalized}</span></div>}
              {r && r.reason && s !== 'ok' && <div style={{ marginTop: 6, color: s === 'bad' ? 'var(--err, #a3261b)' : 'var(--warn, #b76f00)' }}>{r.reason}</div>}
            </div>
            {r && r.suggestion && onApply && (
              <button onClick={() => { onApply(r.suggestion); setOpen(false); }}
                style={{ marginTop: 10, width: '100%', padding: '8px 10px', fontSize: 11,
                  background: 'var(--accent)', color: 'var(--accent-ink)', border: 'none', cursor: 'pointer',
                  fontWeight: 600 }}>
                Apply fix → <span className="ff-mono">{r.suggestion}</span>
              </button>)}
            {r && r.suggestion && !onApply && (
              <div style={{ marginTop: 10, padding: '6px 8px', fontSize: 11,
                background: 'var(--bg-2)', color: 'var(--ink-2)', border: '1px solid var(--rule)' }}>
                Suggested: <span className="ff-mono">{r.suggestion}</span>
              </div>)}
            <div style={{ marginTop: 10, fontSize: 10, color: 'var(--ink-3)' }}>
              <span style={{ opacity: 0.7 }}>Example: </span><span className="ff-mono">{fmt.example}</span>
            </div>
          </Popover>)}
      </>);
  }

  function IdInput({ kind, value, onChange, placeholder, autoFormat: af, ...rest }) {
    const [touched, setTouched] = useState(false);
    const r = useMemo(() => (window.IdCodes && value) ? window.IdCodes.validate(kind, value) : null, [kind, value]);
    const fmt = (window.IdCodes && window.IdCodes.formats[kind]) || { label: kind };
    const s = statusOf(r);
    const showErr = touched && s === 'bad';
    const showWarn = touched && s === 'warn';

    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
        <div style={{ display: 'flex', alignItems: 'stretch', gap: 6 }}>
          <input
            value={value || ''}
            onChange={(e) => onChange(e.target.value)}
            onBlur={() => {
              setTouched(true);
              if (af && r && r.valid === true && r.normalized && r.normalized !== value) onChange(r.normalized);
            }}
            placeholder={placeholder || fmt.example}
            className="ff-mono"
            style={{ flex: 1, fontSize: 12, padding: '6px 8px', minWidth: 120,
              background: 'var(--bg)',
              border: '1px solid ' + (showErr ? 'var(--err, #a3261b)' : showWarn ? 'var(--warn, #b76f00)' : 'var(--rule)'),
              outline: 'none', color: 'var(--ink)' }}
            {...rest} />
          {touched && s !== 'empty' && s !== 'unknown' && (
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '0 6px', border: '1px solid var(--rule)' }}>
              <StatusDot s={s} />
            </span>)}
        </div>
        {showErr && r && r.reason && (
          <div style={{ fontSize: 10, color: 'var(--err, #a3261b)' }}>
            {r.reason}
            {r.suggestion && (
              <button onClick={() => { onChange(r.suggestion); setTouched(false); }}
                className="ff-mono"
                style={{ marginLeft: 8, padding: '1px 6px', fontSize: 10,
                  background: 'transparent', border: '1px solid currentColor',
                  color: 'inherit', cursor: 'pointer' }}>
                fix → {r.suggestion}
              </button>)}
          </div>)}
        {showWarn && r && r.reason && (
          <div style={{ fontSize: 10, color: 'var(--warn, #b76f00)' }}>{r.reason}</div>)}
      </div>);
  }

  window.IdChip = IdChip;
  window.IdInput = IdInput;
})();
