// ui2.jsx — v2 premium primitives. Same component names/props as v1 so the
// admin dashboard and any legacy view restyle for free.
const { useState, useRef, useCallback } = React;

// Serif accent text (replaces v1 gradient/script treatment)
function GradientText({ children, style = {} }) {
  return <span style={{ fontFamily: T.font.display, fontWeight: 600, color: T.color.text, letterSpacing: 0.2, ...style }}>{children}</span>;
}

function Card({ children, style = {}, ...rest }) {
  return <div style={{ background: T.color.card, border: '1px solid ' + T.color.border, borderRadius: T.radius.card, boxShadow: T.shadow.soft, ...style }} {...rest}>{children}</div>;
}

function Divider({ style = {} }) {
  return <div style={{ height: 1, background: T.grad.divider, opacity: 0.8, ...style }} />;
}

function Badge({ children, tone = 'amber', style = {} }) {
  const map = {
    amber: { bg: T.color.accentSoft, fg: T.color.accentDeep },
    sage: { bg: T.color.sageLight, fg: T.color.sageDeep },
    neutral: { bg: 'transparent', fg: T.color.textSoft },
  };
  const c = map[tone] || map.amber;
  return <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, background: c.bg, color: c.fg, border: '1px solid ' + (tone === 'neutral' ? T.color.border : 'transparent'), fontFamily: T.font.head, fontWeight: 700, fontSize: 11, letterSpacing: 1.2, textTransform: 'uppercase', padding: '4px 11px', borderRadius: 100, ...style }}>{children}</span>;
}

function Btn({ children, variant = 'primary', disabled, onClick, type = 'button', style = {}, full, ...rest }) {
  const base = {
    fontFamily: T.font.head, fontWeight: 700, fontSize: 14.5, letterSpacing: 0.3, borderRadius: T.radius.btn,
    padding: '14px 26px', cursor: disabled ? 'not-allowed' : 'pointer', border: '1px solid transparent',
    display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
    width: full ? '100%' : undefined,
    transition: 'transform .16s ease, box-shadow .22s ease, background .22s ease, color .22s ease, border-color .22s ease, opacity .2s',
    WebkitTapHighlightColor: 'transparent', lineHeight: 1.1,
  };
  const variants = {
    primary: {
      background: disabled ? T.color.border : T.color.text,
      color: disabled ? T.color.textFaint : T.color.bg,
      boxShadow: disabled ? 'none' : '0 10px 24px rgba(34,27,18,0.18)',
    },
    secondary: { background: T.color.accentSoft, color: T.color.accentDeep },
    ghost: { background: 'transparent', color: T.color.textSoft, borderColor: T.color.border },
    link: { background: 'transparent', color: T.color.link, boxShadow: 'none', padding: '6px 8px', fontSize: 14 },
  };
  return (
    <button type={type} disabled={disabled} onClick={onClick} className="bol-btn" data-v={variant}
      style={{ ...base, ...(variants[variant] || variants.primary), opacity: disabled ? 0.7 : 1, ...style }} {...rest}>
      {children}
    </button>
  );
}

function Field({ label, hint, children }) {
  return (
    <label style={{ display: 'block', marginBottom: 18 }}>
      <div style={{ fontFamily: T.font.head, fontWeight: 800, fontSize: 12, letterSpacing: 1.1, textTransform: 'uppercase', color: T.color.textSoft, marginBottom: 8 }}>{label}</div>
      {children}
      {hint && <div style={{ fontFamily: T.font.body, fontSize: 12.5, color: T.color.textFaint, marginTop: 7 }}>{hint}</div>}
    </label>
  );
}

function Input({ label, hint, value, onChange, type = 'text', placeholder, uppercase, ...rest }) {
  return (
    <Field label={label} hint={hint}>
      <input className="bol-input" type={type} value={value} placeholder={placeholder}
        onChange={(e) => onChange(uppercase ? e.target.value.toUpperCase() : e.target.value)}
        style={{
          width: '100%', boxSizing: 'border-box', fontFamily: T.font.body, fontSize: 16, color: T.color.text,
          background: T.color.field, border: '1px solid ' + T.color.border, borderRadius: T.radius.input,
          padding: '13px 15px', outline: 'none', transition: 'border-color .18s, box-shadow .18s',
          letterSpacing: uppercase ? 1.5 : 0,
        }} {...rest} />
    </Field>
  );
}

function CountedTextarea({ label, value, onChange, max = 500, rows = 3, placeholder }) {
  const len = (value || '').length;
  const near = len > max * 0.9;
  return (
    <Field label={label}>
      <div style={{ position: 'relative' }}>
        <textarea className="bol-input" rows={rows} value={value} placeholder={placeholder}
          onChange={(e) => onChange(e.target.value.slice(0, max))}
          style={{
            width: '100%', boxSizing: 'border-box', fontFamily: T.font.body, fontSize: 15.5, lineHeight: 1.55, color: T.color.text,
            background: T.color.field, border: '1px solid ' + T.color.border, borderRadius: T.radius.input,
            padding: '13px 15px', outline: 'none', resize: 'vertical', transition: 'border-color .18s, box-shadow .18s',
          }} />
        <div style={{ position: 'absolute', right: 10, bottom: 9, fontFamily: T.font.body, fontSize: 11, color: near ? T.color.accent : T.color.textFaint, background: rgba('#FFFFFF', 0.001), padding: '1px 6px', pointerEvents: 'none' }}>{len}/{max}</div>
      </div>
    </Field>
  );
}

function ProgressBar({ step, total }) {
  return (
    <div style={{ marginBottom: 26 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 9 }}>
        <span style={{ fontFamily: T.font.head, fontWeight: 800, fontSize: 11, color: T.color.accentDeep, letterSpacing: 1.8, textTransform: 'uppercase' }}>Step {step} of {total}</span>
        <span style={{ fontFamily: T.font.body, fontSize: 12, color: T.color.textFaint }}>{Math.round(step / total * 100)}%</span>
      </div>
      <div style={{ height: 3, borderRadius: 100, background: T.color.border, overflow: 'hidden' }}>
        <div style={{ height: '100%', width: step / total * 100 + '%', borderRadius: 100, background: T.color.accent, transition: 'width .45s cubic-bezier(.3,.7,.2,1)' }} />
      </div>
    </div>
  );
}

function StarRating({ value, onChange, size = 34 }) {
  const [hover, setHover] = useState(0);
  return (
    <div style={{ display: 'flex', gap: 6 }} onMouseLeave={() => setHover(0)}>
      {[1, 2, 3, 4, 5].map((n) => {
        const active = (hover || value) >= n;
        return (
          <button key={n} type="button" aria-label={n + ' star' + (n > 1 ? 's' : '')}
            onClick={() => onChange(n === value ? 0 : n)} onMouseEnter={() => setHover(n)}
            style={{
              background: 'none', border: 'none', cursor: 'pointer', padding: 2, lineHeight: 1,
              fontSize: size, color: active ? T.color.accent : T.color.border,
              transform: hover === n ? 'scale(1.18)' : 'scale(1)',
              transition: 'transform .18s cubic-bezier(.3,.7,.2,1.4), color .15s',
            }}>★</button>
        );
      })}
    </div>
  );
}

function Pill({ children, selected, onClick }) {
  return (
    <button type="button" onClick={onClick}
      style={{
        fontFamily: T.font.head, fontWeight: 700, fontSize: 13.5, cursor: 'pointer',
        padding: '9px 17px', borderRadius: 100, transition: 'all .18s ease',
        border: '1px solid ' + (selected ? T.color.text : T.color.border),
        background: selected ? T.color.text : 'transparent', color: selected ? T.color.bg : T.color.textSoft,
      }}>{children}</button>
  );
}

// ── File uploader ─────────────────────────────────────────────
const OK_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'application/pdf'];
const MAX_FILES = 3, MAX_BYTES = 5 * 1024 * 1024;

function FileUploader({ files, onChange }) {
  const inputRef = useRef(null);
  const [drag, setDrag] = useState(false);
  const [err, setErr] = useState('');

  const readFile = (file) => new Promise((res, rej) => {
    const r = new FileReader();
    r.onload = () => res({ name: file.name, type: file.type, size: file.size, data: r.result });
    r.onerror = rej; r.readAsDataURL(file);
  });

  const add = useCallback(async (fileList) => {
    setErr('');
    const incoming = Array.from(fileList);
    let next = files.slice();
    for (const f of incoming) {
      if (next.length >= MAX_FILES) { setErr('Up to ' + MAX_FILES + ' files.'); break; }
      if (!OK_TYPES.includes(f.type)) { setErr('Only images or PDFs, please.'); continue; }
      if (f.size > MAX_BYTES) { setErr('“' + f.name + '” is over 5MB.'); continue; }
      next.push(await readFile(f));
    }
    onChange(next.slice(0, MAX_FILES));
  }, [files, onChange]);

  return (
    <div>
      <div
        onClick={() => inputRef.current && inputRef.current.click()}
        onDragOver={(e) => { e.preventDefault(); setDrag(true); }}
        onDragLeave={() => setDrag(false)}
        onDrop={(e) => { e.preventDefault(); setDrag(false); add(e.dataTransfer.files); }}
        style={{
          cursor: 'pointer', textAlign: 'center', padding: '24px 16px',
          border: '1px dashed ' + (drag ? T.color.accent : T.color.border), borderRadius: T.radius.input,
          background: drag ? T.color.accentSoft : 'transparent', transition: 'all .18s', color: T.color.textSoft,
        }}>
        <div style={{ width: 34, height: 34, margin: '0 auto 8px', borderRadius: 100, border: '1px solid ' + T.color.border, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 18, fontWeight: 400, color: T.color.textSoft, lineHeight: 1 }}>+</div>
        <div style={{ fontFamily: T.font.head, fontWeight: 700, fontSize: 13.5, color: T.color.text }}>Tap or drop files to upload</div>
        <div style={{ fontFamily: T.font.body, fontSize: 12.5, color: T.color.textFaint, marginTop: 3 }}>Images or PDF · up to 3 files · 5MB each</div>
        <input ref={inputRef} type="file" accept={OK_TYPES.join(',')} multiple style={{ display: 'none' }}
          onChange={(e) => { add(e.target.files); e.target.value = ''; }} />
      </div>
      {err && <div style={{ fontFamily: T.font.body, fontSize: 12.5, color: T.color.danger, marginTop: 8 }}>{err}</div>}
      {files.length > 0 &&
        <div style={{ marginTop: 12 }}>
          <div style={{ fontFamily: T.font.body, fontSize: 12.5, color: T.color.textSoft, marginBottom: 8 }}>{files.length}/{MAX_FILES} files</div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
            {files.map((f, i) =>
              <div key={i} style={{ position: 'relative', width: 76, height: 76, borderRadius: 10, overflow: 'hidden', border: '1px solid ' + T.color.border, background: T.color.field, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                {f.type.startsWith('image/') ?
                  <img src={f.data} alt={f.name} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> :
                  <div style={{ fontFamily: T.font.head, fontWeight: 800, fontSize: 12, letterSpacing: 1, color: T.color.textSoft }}>PDF</div>}
                <button type="button" aria-label={'Remove ' + f.name}
                  onClick={(e) => { e.stopPropagation(); onChange(files.filter((_, j) => j !== i)); }}
                  style={{ position: 'absolute', top: 3, right: 3, width: 20, height: 20, borderRadius: 100, border: 'none', background: 'rgba(34,27,18,0.75)', color: '#fff', fontSize: 12, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', lineHeight: 1 }}>×</button>
              </div>
            )}
          </div>
        </div>
      }
    </div>
  );
}

Object.assign(window, { GradientText, Card, Divider, Badge, Btn, Field, Input, CountedTextarea, ProgressBar, StarRating, Pill, FileUploader });
