// components.jsx — shared UI for BeanScriptor
// CoffeeBean glyph, BeanSlider, FlavorWheel, glass surfaces.

const PALETTE = {
  espresso: '#241712',
  coffee: '#4A2D22',
  cocoa: '#7A4A36',
  caramel: '#B8794A',
  crema: '#F4E8D5',
  cream: '#FBF7EF',
  paper: '#FFFCF6',
  ink: '#1B120D',
  inkMuted: 'rgba(36, 23, 18, 0.55)',
  inkSoft: 'rgba(36, 23, 18, 0.32)',
  hairline: 'rgba(36, 23, 18, 0.08)',
  sage: 'oklch(62% 0.06 145)',
  sageDeep: 'oklch(48% 0.07 148)',
  tg: '#2B7CD9',
  tgSoft: 'rgba(43, 124, 217, 0.10)',
};

// ─────────────────────────────────────────────────────────────
// CoffeeBean — the signature glyph
// ─────────────────────────────────────────────────────────────
function CoffeeBean({ size = 20, color = PALETTE.coffee, fill = true, tilt = -18, style = {} }) {
  const c = color;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24"
         style={{ transform: `rotate(${tilt}deg)`, display: 'block', ...style }}>
      <ellipse cx="12" cy="12" rx="7.2" ry="9.6"
               fill={fill ? c : 'none'} stroke={c} strokeWidth={fill ? 0 : 1.6} />
      <path d="M12 3.2 C 9.5 7, 9.5 17, 12 20.8" fill="none"
            stroke={fill ? PALETTE.crema : c} strokeOpacity={fill ? 0.55 : 1}
            strokeWidth="1.4" strokeLinecap="round" />
      {fill && (
        <ellipse cx="9.5" cy="8" rx="1.4" ry="2.2" fill="#fff" opacity="0.18" />
      )}
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Glass surface — frosted card
// ─────────────────────────────────────────────────────────────
function GlassCard({ children, style = {}, padding = 16, radius = 22 }) {
  return (
    <div style={{
      background: 'linear-gradient(180deg, rgba(255,252,246,0.85), rgba(244,232,213,0.55))',
      backdropFilter: 'blur(20px) saturate(140%)',
      WebkitBackdropFilter: 'blur(20px) saturate(140%)',
      border: `0.5px solid ${PALETTE.hairline}`,
      borderRadius: radius,
      padding,
      boxShadow: '0 1px 0 rgba(255,255,255,0.6) inset, 0 8px 24px -12px rgba(36,23,18,0.18)',
      ...style,
    }}>
      {children}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Section heading (label + optional kicker)
// ─────────────────────────────────────────────────────────────
function SectionLabel({ children, kicker, style = {} }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
      padding: '0 4px 8px', ...style,
    }}>
      <div style={{
        fontSize: 11, fontWeight: 600, letterSpacing: 1.4, textTransform: 'uppercase',
        color: PALETTE.inkMuted,
      }}>{children}</div>
      {kicker && <div style={{ fontSize: 11, color: PALETTE.inkSoft, letterSpacing: 0.3 }}>{kicker}</div>}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// BeanSlider — horizontal slider with bean thumb + tick marks
// ─────────────────────────────────────────────────────────────
function BeanSlider({ value, onChange, min = 0, max = 10, step = 1, ticks, leftLabel, rightLabel }) {
  const trackRef = React.useRef(null);
  const [drag, setDrag] = React.useState(false);
  const pct = (value - min) / (max - min);

  const handleMove = (clientX) => {
    if (!trackRef.current) return;
    const rect = trackRef.current.getBoundingClientRect();
    let p = (clientX - rect.left) / rect.width;
    p = Math.max(0, Math.min(1, p));
    const raw = min + p * (max - min);
    const snapped = Math.round(raw / step) * step;
    onChange(Math.max(min, Math.min(max, snapped)));
  };
  // The drag effect only re-runs when drag flips — route through a ref so
  // mid-drag moves always see the current onChange/min/max/step.
  const handleMoveRef = React.useRef(handleMove);
  handleMoveRef.current = handleMove;

  React.useEffect(() => {
    if (!drag) return;
    const onMove = (e) => {
      if (e.touches) e.preventDefault(); // keep the page from scrolling under the drag
      handleMoveRef.current(e.touches ? e.touches[0].clientX : e.clientX);
    };
    const onUp = () => setDrag(false);
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    window.addEventListener('touchmove', onMove, { passive: false });
    window.addEventListener('touchend', onUp);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
      window.removeEventListener('touchmove', onMove);
      window.removeEventListener('touchend', onUp);
    };
  }, [drag]);

  const tickMarks = ticks || Array.from({ length: max - min + 1 }, (_, i) => min + i);

  return (
    <div style={{ width: '100%', userSelect: 'none' }}>
      <div
        ref={trackRef}
        onMouseDown={(e) => { setDrag(true); handleMove(e.clientX); }}
        onTouchStart={(e) => { setDrag(true); handleMove(e.touches[0].clientX); }}
        style={{
          position: 'relative', height: 36, cursor: 'pointer',
          display: 'flex', alignItems: 'center',
        }}
      >
        {/* track */}
        <div style={{
          position: 'absolute', left: 12, right: 12, height: 4,
          background: 'rgba(36,23,18,0.08)', borderRadius: 4,
        }} />
        {/* fill */}
        <div style={{
          position: 'absolute', left: 12, height: 4,
          width: `calc((100% - 24px) * ${pct})`,
          background: `linear-gradient(90deg, ${PALETTE.caramel}, ${PALETTE.coffee})`,
          borderRadius: 4,
        }} />
        {/* ticks */}
        {tickMarks.map((t) => {
          const tp = (t - min) / (max - min);
          const active = t <= value;
          return (
            <div key={t} style={{
              position: 'absolute', left: `calc(12px + (100% - 24px) * ${tp})`,
              transform: 'translateX(-50%)',
              width: 2, height: 8, borderRadius: 1,
              background: active ? PALETTE.coffee : 'rgba(36,23,18,0.18)',
            }} />
          );
        })}
        {/* thumb */}
        <div style={{
          position: 'absolute',
          left: `calc(12px + (100% - 24px) * ${pct})`,
          transform: `translateX(-50%) scale(${drag ? 1.12 : 1})`,
          transition: 'transform 120ms ease',
          filter: drag ? 'drop-shadow(0 4px 10px rgba(36,23,18,0.35))' : 'drop-shadow(0 2px 4px rgba(36,23,18,0.25))',
        }}>
          <CoffeeBean size={26} color={PALETTE.espresso} tilt={-22} />
        </div>
      </div>
      {(leftLabel || rightLabel) && (
        <div style={{
          display: 'flex', justifyContent: 'space-between',
          fontSize: 11, color: PALETTE.inkMuted, padding: '4px 4px 0',
          fontVariantCaps: 'all-small-caps', letterSpacing: 0.6,
        }}>
          <span>{leftLabel}</span>
          <span>{rightLabel}</span>
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// FlavorWheel — 8 clickable sectors with optional sub-petals
// ─────────────────────────────────────────────────────────────
const FLAVORS = [
  { key: 'fruity',    label: 'Fruity',    hue: 8,   notes: ['Berry', 'Citrus', 'Stone Fruit', 'Tropical'] },
  { key: 'sweet',     label: 'Sweet',     hue: 35,  notes: ['Honey', 'Caramel', 'Brown Sugar', 'Maple'] },
  { key: 'nutty',     label: 'Nutty',     hue: 28,  notes: ['Almond', 'Hazelnut', 'Cocoa', 'Chocolate'] },
  { key: 'roasty',    label: 'Roasty',    hue: 18,  notes: ['Smoke', 'Tobacco', 'Burnt', 'Ash'] },
  { key: 'spicy',     label: 'Spicy',     hue: 348, notes: ['Pepper', 'Clove', 'Anise', 'Cardamom'] },
  { key: 'veggie',    label: 'Veggie',    hue: 130, notes: ['Herb', 'Grass', 'Pea', 'Olive Oil'] },
  { key: 'sour',      label: 'Sour',      hue: 60,  notes: ['Citric', 'Malic', 'Lactic', 'Phosphoric'] },
  { key: 'floral',    label: 'Floral',    hue: 320, notes: ['Jasmine', 'Rose', 'Chamomile', 'Bergamot'] },
];

function flavorColor(hue, sat = 0.08, l = 70, a = 1) {
  return `oklch(${l}% ${sat} ${hue} / ${a})`;
}

function FlavorWheel({ active = [], onToggle, size = 280 }) {
  const cx = size / 2, cy = size / 2;
  const rOuter = size / 2 - 4;
  const rInner = size / 2 - 70;
  const rCore = 28;
  const sectors = FLAVORS.length;
  const sweep = (2 * Math.PI) / sectors;

  // build sector path
  const sectorPath = (i, r1, r2) => {
    const a0 = -Math.PI / 2 + i * sweep - sweep / 2;
    const a1 = a0 + sweep;
    const x0 = cx + r2 * Math.cos(a0), y0 = cy + r2 * Math.sin(a0);
    const x1 = cx + r2 * Math.cos(a1), y1 = cy + r2 * Math.sin(a1);
    const x2 = cx + r1 * Math.cos(a1), y2 = cy + r1 * Math.sin(a1);
    const x3 = cx + r1 * Math.cos(a0), y3 = cy + r1 * Math.sin(a0);
    return `M ${x0} ${y0} A ${r2} ${r2} 0 0 1 ${x1} ${y1} L ${x2} ${y2} A ${r1} ${r1} 0 0 0 ${x3} ${y3} Z`;
  };

  const labelPos = (i, r) => {
    const a = -Math.PI / 2 + i * sweep;
    return [cx + r * Math.cos(a), cy + r * Math.sin(a)];
  };

  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: 'block' }}>
      <defs>
        <radialGradient id="wheelCenter" cx="0.5" cy="0.5" r="0.5">
          <stop offset="0%" stopColor={PALETTE.cream} />
          <stop offset="100%" stopColor={PALETTE.crema} />
        </radialGradient>
      </defs>
      {/* outer ring backdrop */}
      <circle cx={cx} cy={cy} r={rOuter} fill="rgba(36,23,18,0.03)" />
      {FLAVORS.map((f, i) => {
        const isOn = active.includes(f.key);
        const fill = isOn ? flavorColor(f.hue, 0.16, 72, 1) : flavorColor(f.hue, 0.04, 92, 1);
        const stroke = isOn ? flavorColor(f.hue, 0.18, 50) : 'rgba(36,23,18,0.08)';
        return (
          <g key={f.key} style={{ cursor: 'pointer' }} onClick={() => onToggle && onToggle(f.key)}>
            <path d={sectorPath(i, rInner, rOuter)} fill={fill} stroke={stroke} strokeWidth={isOn ? 1.2 : 0.5} />
          </g>
        );
      })}
      {/* labels */}
      {FLAVORS.map((f, i) => {
        const [x, y] = labelPos(i, (rInner + rOuter) / 2);
        const isOn = active.includes(f.key);
        return (
          <text key={f.key} x={x} y={y} dy="0.35em" textAnchor="middle"
                style={{
                  fontSize: 11, fontWeight: isOn ? 700 : 600,
                  fill: isOn ? PALETTE.espresso : PALETTE.coffee,
                  letterSpacing: 0.3, pointerEvents: 'none',
                  fontFamily: '-apple-system, system-ui',
                }}>
            {f.label}
          </text>
        );
      })}
      {/* core */}
      <circle cx={cx} cy={cy} r={rInner - 2} fill="url(#wheelCenter)" stroke={PALETTE.hairline} />
      {/* center bean */}
      <g transform={`translate(${cx - 12}, ${cy - 12})`}>
        <foreignObject x="0" y="0" width="24" height="24">
          <CoffeeBean size={24} color={PALETTE.espresso} tilt={-22} />
        </foreignObject>
      </g>
      {/* count badge */}
      <text x={cx} y={cy + 22} textAnchor="middle"
            style={{ fontSize: 10, fontWeight: 600, fill: PALETTE.inkMuted, letterSpacing: 0.6 }}>
        {active.length} SELECTED
      </text>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Tag chip
// ─────────────────────────────────────────────────────────────
function Chip({ children, active, icon, onClick, style = {} }) {
  return (
    <button onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '7px 12px',
      borderRadius: 999,
      fontSize: 13, fontWeight: 500,
      border: `0.5px solid ${active ? PALETTE.espresso : PALETTE.hairline}`,
      background: active ? PALETTE.espresso : 'rgba(255,252,246,0.7)',
      color: active ? PALETTE.crema : PALETTE.coffee,
      cursor: 'pointer',
      backdropFilter: 'blur(10px)',
      transition: 'all 150ms ease',
      ...style,
    }}>
      {icon && <span style={{ fontSize: 14 }}>{icon}</span>}
      {children}
    </button>
  );
}

// ─────────────────────────────────────────────────────────────
// Field helpers
// ─────────────────────────────────────────────────────────────
function FieldShell({ label, suffix, children, span = 1 }) {
  return (
    <div style={{
      gridColumn: `span ${span}`,
      background: 'rgba(255,252,246,0.65)',
      border: `0.5px solid ${PALETTE.hairline}`,
      borderRadius: 16, padding: '10px 12px',
      display: 'flex', flexDirection: 'column', gap: 2,
      position: 'relative',
    }}>
      <div style={{ fontSize: 10, fontWeight: 600, letterSpacing: 1, textTransform: 'uppercase',
                    color: PALETTE.inkMuted }}>
        {label}
      </div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 4 }}>
        {children}
        {suffix && <span style={{ fontSize: 12, color: PALETTE.inkMuted, fontWeight: 500 }}>{suffix}</span>}
      </div>
    </div>
  );
}

// Character filter for numeric fields. mode 'int' keeps digits only;
// 'decimal' keeps digits and at most one dot. Commas become dots — the iOS
// decimal keypad shows only a comma in many locales (ru, de, fr, …), so
// blocking it would make decimal input impossible on those devices.
// Applied to the whole value on change, so pasted text is filtered too.
function sanitizeNumeric(raw, mode = 'decimal') {
  let v = String(raw).replace(/,/g, '.');
  v = mode === 'int' ? v.replace(/[^\d]/g, '') : v.replace(/[^\d.]/g, '');
  if (mode !== 'int') {
    const i = v.indexOf('.');
    if (i !== -1) v = v.slice(0, i + 1) + v.slice(i + 1).replace(/\./g, '');
  }
  return v;
}

function NumField({ label, suffix, value, onChange, span = 1, mode = 'decimal', maxLength }) {
  return (
    <FieldShell label={label} suffix={suffix} span={span}>
      <input
        type="text"
        inputMode={mode === 'int' ? 'numeric' : 'decimal'}
        maxLength={maxLength}
        value={value}
        onChange={(e) => onChange(sanitizeNumeric(e.target.value, mode))}
        style={{
          background: 'transparent', border: 'none', outline: 'none',
          fontSize: 18, fontWeight: 600, color: PALETTE.espresso,
          fontFeatureSettings: '"tnum"', width: '100%',
          fontFamily: '-apple-system, system-ui',
          padding: 0,
        }}
      />
    </FieldShell>
  );
}

function TextField({ label, value, onChange, placeholder, span = 1 }) {
  return (
    <FieldShell label={label} span={span}>
      <input
        type="text"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        style={{
          background: 'transparent', border: 'none', outline: 'none',
          fontSize: 16, fontWeight: 500, color: PALETTE.espresso,
          width: '100%', padding: 0,
          fontFamily: '-apple-system, system-ui',
        }}
      />
    </FieldShell>
  );
}

// ─────────────────────────────────────────────────────────────
// Tiny inline icons (not lucide; matched for simplicity)
// ─────────────────────────────────────────────────────────────
const Icon = {
  back: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d="M15 18l-6-6 6-6" />
    </svg>
  ),
  plus: (s = 18) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="2.2" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>
  ),
  flame: (s = 14) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 2c1 4 4 5 4 9a4 4 0 1 1-8 0c0-2 1-3 1-5 0 2 2 3 3 1-1-2 0-4 0-5z"/>
    </svg>
  ),
  snow: (s = 14) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="2" strokeLinecap="round">
      <path d="M12 2v20M4 6l16 12M20 6L4 18"/>
    </svg>
  ),
  clock: (s = 14) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>
    </svg>
  ),
  drop: (s = 14) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 2c-4 6-6 9-6 12a6 6 0 0 0 12 0c0-3-2-6-6-12z"/>
    </svg>
  ),
  chevron: (s = 16) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"
         strokeLinecap="round" strokeLinejoin="round"><path d="M9 6l6 6-6 6"/></svg>
  ),
};

Object.assign(window, {
  PALETTE, CoffeeBean, GlassCard, SectionLabel, BeanSlider,
  FlavorWheel, FLAVORS, Chip, FieldShell, NumField, TextField, Icon,
  sanitizeNumeric,
});
