// Reusable UI primitives
const { useState, useEffect, useRef, useMemo, useCallback } = React;

const Card = ({ children, style, accent, accentWidth = 3, onClick, className = '' }) => (
  <div
    onClick={onClick}
    className={className}
    style={{
      position: 'relative',
      background: 'rgba(255,255,255,0.05)',
      border: '1px solid var(--border)',
      borderRadius: 16,
      backdropFilter: 'blur(10px)',
      WebkitBackdropFilter: 'blur(10px)',
      boxShadow: 'var(--shadow)',
      overflow: 'hidden',
      ...style,
    }}
  >
    {accent && accent !== 'none' && (
      <div style={{
        position: 'absolute', left: 0, top: 0, bottom: 0, width: accentWidth,
        background:
          accent === 'cyan'    ? 'linear-gradient(180deg, var(--cyan), transparent)'
        : accent === 'red'     ? 'linear-gradient(180deg, var(--red), transparent)'
        : accent === 'amber'   ? 'linear-gradient(180deg, var(--amber), transparent)'
        : accent === 'green'   ? 'linear-gradient(180deg, var(--green), transparent)'
        : (accent === 'default' || accent === 'gray') ? 'linear-gradient(180deg, rgba(255,255,255,0.15), transparent)'
        : `linear-gradient(180deg, ${accent}, transparent)`,
      }}/>
    )}
    {children}
  </div>
);

// Toggle switch
const Toggle = ({ on, onChange, color = 'var(--cyan)', size = 'md', disabled }) => {
  const w = size === 'sm' ? 36 : 44;
  const h = size === 'sm' ? 20 : 24;
  const knob = h - 4;
  return (
    <button
      type="button"
      onClick={(e) => { e.stopPropagation(); !disabled && onChange(!on); }}
      style={{
        width: w, height: h, borderRadius: 999,
        border: '1px solid var(--border)',
        background: on ? color : 'rgba(255,255,255,0.08)',
        position: 'relative',
        transition: 'background 200ms ease',
        opacity: disabled ? 0.45 : 1,
        cursor: disabled ? 'not-allowed' : 'pointer',
        padding: 0,
        boxShadow: on ? `0 0 12px ${color}40` : 'none',
      }}
      aria-checked={on}
    >
      <span style={{
        position: 'absolute',
        top: 2,
        left: on ? w - knob - 2 - 1 : 2,
        width: knob, height: knob,
        borderRadius: '50%',
        background: '#fff',
        transition: 'left 220ms cubic-bezier(.5,1.5,.5,1)',
        boxShadow: '0 2px 6px rgba(0,0,0,0.4)',
      }}/>
    </button>
  );
};

// Pill toggle (segmented)
const Segmented = ({ options, value, onChange, size = 'md', disabled = false }) => {
  return (
    <div style={{
      display: 'inline-flex',
      background: 'rgba(255,255,255,0.05)',
      border: '1px solid var(--border)',
      borderRadius: 999,
      padding: 3,
      gap: 0,
      opacity: disabled ? 0.45 : 1,
    }}>
      {options.map(o => (
        <button
          key={o.value}
          onClick={() => !disabled && onChange(o.value)}
          style={{
            border: 'none',
            background: value === o.value ? 'rgba(0,212,255,0.18)' : 'transparent',
            color: value === o.value ? 'var(--cyan)' : 'var(--text-2)',
            padding: size === 'sm' ? '5px 12px' : '7px 16px',
            fontSize: size === 'sm' ? 12 : 13,
            fontWeight: 500,
            borderRadius: 999,
            transition: 'all 180ms ease',
            letterSpacing: 0.2,
            boxShadow: value === o.value ? 'inset 0 0 0 1px rgba(0,212,255,0.25)' : 'none',
            cursor: disabled ? 'not-allowed' : 'pointer',
          }}
        >
          {o.label}
        </button>
      ))}
    </div>
  );
};

const StatusDot = ({ kind = 'green', size = 8, pulse = false }) => {
  const c = kind === 'green' ? '#00e676' : kind === 'red' ? '#ff5252' : kind === 'amber' ? '#ffab40' : '#5a6585';
  return (
    <span style={{
      width: size, height: size,
      borderRadius: '50%',
      background: c,
      display: 'inline-block',
      boxShadow: `0 0 ${size}px ${c}`,
      animation: pulse ? 'pulse-dot 1.4s ease-in-out infinite' : undefined,
    }}/>
  );
};

const Badge = ({ children, color = 'cyan', solid = false, size = 'md' }) => {
  const map = {
    cyan: ['rgba(0,212,255,0.14)', '#00d4ff', 'rgba(0,212,255,0.3)'],
    teal: ['rgba(0,184,148,0.14)', '#00b894', 'rgba(0,184,148,0.3)'],
    green: ['rgba(0,230,118,0.14)', '#00e676', 'rgba(0,230,118,0.3)'],
    red: ['rgba(255,82,82,0.14)', '#ff5252', 'rgba(255,82,82,0.3)'],
    amber: ['rgba(255,171,64,0.14)', '#ffab40', 'rgba(255,171,64,0.3)'],
    info: ['rgba(64,196,255,0.14)', '#40c4ff', 'rgba(64,196,255,0.3)'],
    gray: ['rgba(255,255,255,0.06)', '#8892b0', 'rgba(255,255,255,0.12)'],
  };
  const [bg, fg, br] = map[color] || map.cyan;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: size === 'sm' ? '2px 8px' : '4px 10px',
      borderRadius: 999,
      background: solid ? fg : bg,
      color: solid ? '#0a0e27' : fg,
      border: `1px solid ${br}`,
      fontSize: size === 'sm' ? 11 : 12,
      fontWeight: 500,
      letterSpacing: 0.2,
      whiteSpace: 'nowrap',
    }}>{children}</span>
  );
};

// Primary action button
const Btn = ({ children, onClick, variant = 'primary', size = 'md', icon, full, disabled, style }) => {
  const styles = {
    primary: { bg: 'linear-gradient(135deg, var(--cyan), var(--teal))', fg: '#0a0e27', br: 'transparent' },
    secondary: { bg: 'rgba(255,255,255,0.06)', fg: '#fff', br: 'var(--border)' },
    danger: { bg: 'var(--red)', fg: '#fff', br: 'transparent' },
    ghost: { bg: 'transparent', fg: 'var(--text-2)', br: 'var(--border)' },
  }[variant] || {};
  const padding = size === 'sm' ? '8px 12px' : size === 'lg' ? '14px 20px' : '11px 16px';
  return (
    <button
      onClick={(e)=>{ e.stopPropagation(); !disabled && onClick && onClick(e); }}
      disabled={disabled}
      style={{
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        gap: 8,
        padding,
        background: styles.bg,
        color: styles.fg,
        border: `1px solid ${styles.br}`,
        borderRadius: 12,
        fontWeight: 600,
        fontSize: size === 'sm' ? 12 : 14,
        letterSpacing: 0.2,
        width: full ? '100%' : 'auto',
        opacity: disabled ? 0.45 : 1,
        cursor: disabled ? 'not-allowed' : 'pointer',
        transition: 'transform 120ms ease, filter 120ms ease',
        ...style,
      }}
      onMouseDown={(e)=> e.currentTarget.style.transform = 'scale(0.98)'}
      onMouseUp={(e)=> e.currentTarget.style.transform = 'scale(1)'}
      onMouseLeave={(e)=> e.currentTarget.style.transform = 'scale(1)'}
    >
      {icon && <Ic name={icon} size={size === 'sm' ? 14 : 16}/>}
      {children}
    </button>
  );
};

const Modal = ({ open, onClose, children, title, maxWidth = 360 }) => {
  if (!open) return null;
  // createPortal renders at document.body so position:fixed is always relative
  // to the true viewport — unaffected by parent transforms, animations, or
  // scroll containers that would otherwise shift the dialog off-screen on mobile.
  return ReactDOM.createPortal(
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0,
      background: 'rgba(5,8,20,0.65)',
      backdropFilter: 'blur(6px)',
      zIndex: 1000,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: '20px 20px calc(20px + env(safe-area-inset-bottom, 0px))',
      animation: 'pop-in 180ms ease-out',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth,
        background: 'linear-gradient(180deg, rgba(20,26,55,0.95), rgba(15,20,48,0.95))',
        border: '1px solid var(--border-strong)',
        borderRadius: 20,
        padding: 22,
        boxShadow: '0 20px 60px rgba(0,0,0,0.6)',
        animation: 'pop-in 220ms ease-out',
      }}>
        {title && <h3 style={{margin: '0 0 12px', fontSize: 18, fontWeight: 600}}>{title}</h3>}
        {children}
      </div>
    </div>,
    document.body
  );
};

// Confirmation dialog
const Confirm = ({ open, onCancel, onConfirm, title, body, confirmLabel = 'Confirm', danger = false }) => (
  <Modal open={open} onClose={onCancel} title={title}>
    <p style={{margin: '0 0 18px', color: 'var(--text-2)', fontSize: 14, lineHeight: 1.5}}>{body}</p>
    <div style={{display: 'flex', gap: 10, justifyContent: 'flex-end'}}>
      <Btn variant="ghost" onClick={onCancel}>Cancel</Btn>
      <Btn variant={danger ? 'danger' : 'primary'} onClick={onConfirm}>{confirmLabel}</Btn>
    </div>
  </Modal>
);

// Metric block
const Metric = ({ icon, label, value, unit, tone, flash }) => {
  const toneColor = { green: 'var(--green)', red: 'var(--red)', amber: 'var(--amber)', cyan: 'var(--cyan)' }[tone];
  return (
    <div style={{
      background: 'rgba(255,255,255,0.03)',
      border: '1px solid var(--border)',
      borderRadius: 14,
      padding: 14,
      animation: flash ? 'flash-glow 600ms ease-out' : undefined,
    }}>
      <div style={{display: 'flex', alignItems: 'center', gap: 6, color: 'var(--text-2)', fontSize: 11, fontWeight: 500, letterSpacing: 0.4, textTransform: 'uppercase'}}>
        {icon && <Ic name={icon} size={13} color={toneColor || 'var(--text-2)'}/>}
        {label}
      </div>
      <div style={{marginTop: 6, display: 'baseline', display: 'flex', alignItems: 'baseline', gap: 4}}>
        <span className="num" style={{fontSize: 22, fontWeight: 600, color: toneColor || 'var(--text)'}}>{value}</span>
        {unit && <span style={{color: 'var(--text-2)', fontSize: 12, fontWeight: 500}}>{unit}</span>}
      </div>
    </div>
  );
};

// Section heading
const SectionTitle = ({ children, action }) => (
  <div style={{display: 'flex', alignItems: 'center', justifyContent: 'space-between', margin: '18px 0 10px', padding: '0 4px'}}>
    <h3 style={{margin: 0, fontSize: 13, fontWeight: 500, color: 'var(--text-2)', letterSpacing: 1.4, textTransform: 'uppercase'}}>{children}</h3>
    {action}
  </div>
);

// Slider with value
const SliderRow = ({ label, hint, value, onChange, min = 0, max = 100, step = 1, unit = '%', color = 'var(--cyan)' }) => (
  <div style={{padding: '10px 0'}}>
    <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 8}}>
      <div>
        <div style={{fontSize: 14, fontWeight: 500}}>{label}</div>
        {hint && <div style={{fontSize: 11, color: 'var(--text-3)', marginTop: 2}}>{hint}</div>}
      </div>
      <div className="num" style={{fontSize: 16, fontWeight: 600, color}}>{value}{unit}</div>
    </div>
    <input type="range" min={min} max={max} step={step} value={value} onChange={e => onChange(+e.target.value)} style={{accentColor: color}}/>
  </div>
);

const TextInput = ({ value, onChange, placeholder, type = 'text', icon, suffix, full = true }) => (
  <div style={{
    display: 'flex', alignItems: 'center', gap: 8,
    background: 'rgba(255,255,255,0.04)',
    border: '1px solid var(--border)',
    borderRadius: 12,
    padding: '10px 12px',
    width: full ? '100%' : undefined,
  }}>
    {icon && <Ic name={icon} size={16} color="var(--text-2)"/>}
    <input
      type={type}
      value={value}
      onChange={e => onChange(e.target.value)}
      placeholder={placeholder}
      style={{
        background: 'transparent', border: 'none', outline: 'none',
        color: 'var(--text)', fontSize: 14, flex: 1, minWidth: 0,
      }}
    />
    {suffix && <span style={{color: 'var(--text-3)', fontSize: 12}}>{suffix}</span>}
  </div>
);

// Animated pending-dots indicator for ACK-waiting state.
// size: 'sm' (12px) | 'md' (16px) | 'lg' (22px)
const PendingDots = ({ size = 'md', color = 'var(--text-2)' }) => {
  const [step, setStep] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setStep(s => (s + 1) % 3), 380);
    return () => clearInterval(id);
  }, []);
  const sz = size === 'lg' ? 22 : size === 'sm' ? 12 : 16;
  return (
    <span style={{
      display: 'inline-block', fontFamily: 'monospace', fontWeight: 700,
      fontSize: sz, letterSpacing: 3, color,
      minWidth: sz * 2.4, textAlign: 'center',
    }}>
      {'···'.slice(0, step + 1)}
    </span>
  );
};

Object.assign(window, { Card, Toggle, Segmented, StatusDot, Badge, Btn, Modal, Confirm, Metric, SectionTitle, SliderRow, TextInput, PendingDots });

// Swipe-to-navigate hook — attach returned handlers to detail screen's root div.
// Swipe left → next tab; swipe right → prev tab (or onBack if on first tab).
const useSwipeTabs = (tabs, tab, setTab, onBack) => {
  const sx = useRef(null);
  const sy = useRef(null);
  const onTouchStart = useCallback((e) => {
    sx.current = e.touches[0].clientX;
    sy.current = e.touches[0].clientY;
  }, []);
  const onTouchEnd = useCallback((e) => {
    if (sx.current === null) return;
    const dx = e.changedTouches[0].clientX - sx.current;
    const dy = Math.abs(e.changedTouches[0].clientY - sy.current);
    sx.current = null; sy.current = null;
    if (Math.abs(dx) < 60 || dy > Math.abs(dx)) return;
    const idx = tabs.findIndex(t => t.key === tab);
    if (dx < 0) {
      if (idx < tabs.length - 1) setTab(tabs[idx + 1].key);
    } else {
      if (idx > 0) setTab(tabs[idx - 1].key);
      else if (onBack) onBack();
    }
  }, [tabs, tab, setTab, onBack]);
  return { onTouchStart, onTouchEnd };
};
window.useSwipeTabs = useSwipeTabs;
