// SkinJourney Dashboard — shared UI primitives
// Exported to window: Icon, Avatar, Chip, Button, IconButton, Card, KPI,
// Sparkline, Bars, Skeleton, Toast, Modal, Confirm, Tabs, Tag, PhotoSlot.

const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ── Icons (line, ~1.8 stroke, rounded caps) ─────────────────────────── */
const ICONS = {
  overview: 'M3 12 L9 6 L15 11 L21 5 M3 19 L21 19',
  patients: 'M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2 M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8 M22 21v-2a4 4 0 0 0-3-3.87 M16 3.13a4 4 0 0 1 0 7.75',
  calendar: 'M3 8h18 M5 5h14a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2 M8 3v4 M16 3v4',
  appointments: 'M12 8v4l3 2 M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0',
  settings: 'M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1A1.7 1.7 0 0 0 9 19.4a1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1A1.7 1.7 0 0 0 4.6 9a1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9c.4.2 1 .4 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1Z',
  search: 'M21 21l-4.3-4.3 M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z',
  bell: 'M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9 M10.3 21a1.94 1.94 0 0 0 3.4 0',
  copy: 'M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2 M15 2H9a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1Z',
  check: 'M20 6L9 17l-5-5',
  x: 'M18 6 6 18 M6 6l12 12',
  plus: 'M12 5v14 M5 12h14',
  minus: 'M5 12h14',
  arrow_left: 'M19 12H5 M12 19l-7-7 7-7',
  arrow_right: 'M5 12h14 M12 5l7 7-7 7',
  chevron_down: 'M6 9l6 6 6-6',
  chevron_left: 'M15 18l-6-6 6-6',
  chevron_right: 'M9 18l6-6-6-6',
  download: 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4 M7 10l5 5 5-5 M12 15V3',
  upload: 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4 M17 8l-5-5-5 5 M12 3v12',
  pdf: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6 M9 13h6 M9 17h6',
  qr: 'M3 3h7v7H3z M14 3h7v7h-7z M3 14h7v7H3z M14 14h3v3h-3z M14 19h3 M19 14v3 M19 19h2',
  trend_up: 'M3 17l6-6 4 4 8-8 M14 7h7v7',
  trend_down: 'M3 7l6 6 4-4 8 8 M14 17h7v-7',
  flag: 'M4 22V4a1 1 0 0 1 1-1h13l-3 5 3 5H5 M4 13v9',
  camera: 'M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z M12 17a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z',
  note: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6 M16 13H8 M16 17H8 M10 9H8',
  heart: 'M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z',
  leaf: 'M12 22s8-4 8-12V4l-4 2-4-2-4 2-4-2v6c0 8 8 12 8 12Z M12 10v12',
  logout: 'M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4 M16 17l5-5-5-5 M21 12H9',
  share: 'M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8 M16 6l-4-4-4 4 M12 2v13',
  filter: 'M22 3H2l8 9.46V19l4 2v-8.54z',
  grid: 'M3 3h7v7H3z M14 3h7v7h-7z M14 14h7v7h-7z M3 14h7v7H3z',
  list: 'M8 6h13 M8 12h13 M8 18h13 M3 6h.01 M3 12h.01 M3 18h.01',
  more: 'M12 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2 M19 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2 M5 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2',
  trash: 'M3 6h18 M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6 M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2',
  edit: 'M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7 M18.5 2.5a2.12 2.12 0 1 1 3 3L12 15l-4 1 1-4z',
  eye: 'M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8 M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z',
  sun: 'M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10 M12 1v2 M12 21v2 M4.2 4.2l1.4 1.4 M18.4 18.4l1.4 1.4 M1 12h2 M21 12h2 M4.2 19.8l1.4-1.4 M18.4 5.6l1.4-1.4',
  command: 'M18 3h-3a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3h3a3 3 0 0 0 3-3v-3a3 3 0 0 0-3-3H6a3 3 0 0 0-3 3v3a3 3 0 0 0 3 3h3a3 3 0 0 0 3-3V6a3 3 0 0 0-3-3H6a3 3 0 0 0-3 3v3a3 3 0 0 0 3 3h12a3 3 0 0 0 3-3V6a3 3 0 0 0-3-3z',
};

function Icon({ name, size = 20, stroke = 1.8, style, ...rest }) {
  const d = ICONS[name];
  if (!d) return null;
  return (
    <svg
      width={size} height={size} viewBox="0 0 24 24"
      fill="none" stroke="currentColor" strokeWidth={stroke}
      strokeLinecap="round" strokeLinejoin="round"
      style={{ flexShrink: 0, ...style }} aria-hidden="true" {...rest}
    >
      <path d={d} />
    </svg>
  );
}

/* ── Avatar ──────────────────────────────────────────────────────────── */
function Avatar({ name, size = 'md', style, ...rest }) {
  const initial = (name || '?')[0];
  const cls = size === 'sm' ? 'avatar avatar-sm' :
              size === 'lg' ? 'avatar avatar-lg' :
              size === 'xl' ? 'avatar avatar-xl' : 'avatar';
  return <span className={cls} style={style} {...rest}>{initial}</span>;
}

/* ── Chip ────────────────────────────────────────────────────────────── */
function Chip({ children, kind, dot, style, ...rest }) {
  const cls = kind === 'coral' ? 'chip chip-coral' :
              kind === 'warning' ? 'chip chip-warning' :
              kind === 'success' ? 'chip chip-success' :
              kind === 'info' ? 'chip chip-info' :
              kind === 'neutral' ? 'chip chip-neutral' : 'chip';
  return (
    <span className={cls} style={style} {...rest}>
      {dot && <span className="chip-dot" />}
      {children}
    </span>
  );
}

/* ── Button ──────────────────────────────────────────────────────────── */
function Button({ kind = 'secondary', size, icon, iconRight, children, ...rest }) {
  const sz = size === 'sm' ? ' btn-sm' : size === 'lg' ? ' btn-lg' : '';
  return (
    <button className={`btn btn-${kind}${sz}`} {...rest}>
      {icon && <Icon name={icon} size={16} />}
      {children}
      {iconRight && <Icon name={iconRight} size={16} />}
    </button>
  );
}
function IconButton({ icon, size = 18, ...rest }) {
  return (
    <button className="btn-icon" {...rest}>
      <Icon name={icon} size={size} />
    </button>
  );
}

/* ── Card ────────────────────────────────────────────────────────────── */
function Card({ flush, flat, sunken, className = '', children, ...rest }) {
  const cls = ['card', flush && 'card-flush', flat && 'card-flat', sunken && 'card-sunken', className].filter(Boolean).join(' ');
  return <div className={cls} {...rest}>{children}</div>;
}

/* ── KPI ─────────────────────────────────────────────────────────────── */
function CountUp({ value, decimals = 0 }) {
  // No animation — too fragile under screenshot capture. Just show the value.
  return <>{Number(Number(value).toFixed(decimals))}</>;
}

function KPI({ label, value, icon, trend, sparkData, sparkColor, suffix }) {
  return (
    <div className="kpi">
      <div className="kpi-label">
        {icon && <span className="kpi-icon"><Icon name={icon} size={16} /></span>}
        <span>{label}</span>
      </div>
      <div className="kpi-value">
        <CountUp value={value} />{suffix && <span style={{ fontSize: 18, fontWeight: 600, color: 'var(--text-tertiary)', marginInlineStart: 4 }}>{suffix}</span>}
      </div>
      <div className="kpi-meta">
        {trend != null ? (
          <span className={`kpi-trend${trend < 0 ? ' neg' : trend === 0 ? ' neutral' : ''}`}>
            <Icon name={trend < 0 ? 'trend_down' : 'trend_up'} size={14} />
            {trend > 0 ? '+' : ''}{trend}%
          </span>
        ) : <span />}
        {sparkData && <Sparkline data={sparkData} color={sparkColor || 'var(--sage-500)'} />}
      </div>
    </div>
  );
}

/* ── Sparkline ───────────────────────────────────────────────────────── */
function Sparkline({ data, color = 'var(--sage-500)', width = 88, height = 32, fill = true }) {
  if (!data || data.length === 0) return null;
  const max = Math.max(...data, 1);
  const min = Math.min(...data, 0);
  const range = Math.max(max - min, 1);
  const step = width / (data.length - 1 || 1);
  const pts = data.map((v, i) => [i * step, height - 4 - ((v - min) / range) * (height - 8)]);
  const path = pts.map((p, i) => (i === 0 ? `M ${p[0]} ${p[1]}` : `L ${p[0]} ${p[1]}`)).join(' ');
  const area = `${path} L ${width} ${height} L 0 ${height} Z`;
  return (
    <svg className="sparkline" width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
      {fill && <path d={area} fill={color} opacity="0.12" />}
      <path d={path} fill="none" stroke={color} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="2.4" fill={color} />
    </svg>
  );
}

/* ── Bars (weekly cadence) ───────────────────────────────────────────── */
function Bars({ data, max = 3, width = 320, height = 120, color, labels, color2 }) {
  const m = Math.max(max, Math.max(...data, 1));
  const barW = (width - 12) / data.length;
  const gap = Math.max(2, barW * 0.18);
  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
      {/* grid */}
      {[0, 1, 2, 3].map((i) => (
        <line key={i} x1="0" y1={height - 24 - (i / 3) * (height - 36)} x2={width} y2={height - 24 - (i / 3) * (height - 36)}
              stroke="var(--viz-grid)" strokeDasharray="2 4" />
      ))}
      {data.map((v, i) => {
        const h = (v / m) * (height - 36);
        const x = i * barW + 6;
        const y = height - 24 - h;
        const fill = v === 0 ? 'var(--sand-300)' : (color || 'var(--sage-500)');
        return (
          <g key={i}>
            <rect x={x + gap / 2} y={y} width={barW - gap} height={Math.max(2, h)}
                  rx="3" fill={fill} />
            {labels && labels[i] && (
              <text x={x + barW / 2} y={height - 8} fontSize="10" textAnchor="middle" fill="var(--text-tertiary)" fontFamily="var(--font-sans)">
                {labels[i]}
              </text>
            )}
          </g>
        );
      })}
    </svg>
  );
}

/* ── Skeleton ────────────────────────────────────────────────────────── */
function Skeleton({ w = '100%', h = 12, r = 6, style }) {
  return <span className="skeleton" style={{ display: 'inline-block', width: w, height: h, borderRadius: r, ...style }} />;
}

/* ── Toast ───────────────────────────────────────────────────────────── */
const ToastContext = React.createContext({ push: () => {} });
function ToastHost({ children }) {
  const [items, setItems] = useState([]);
  const push = useCallback((text, opts = {}) => {
    const id = Math.random().toString(36).slice(2);
    setItems((cur) => [...cur, { id, text, icon: opts.icon || 'check' }]);
    setTimeout(() => setItems((cur) => cur.filter((t) => t.id !== id)), opts.duration || 2800);
  }, []);
  return (
    <ToastContext.Provider value={{ push }}>
      {children}
      <div className="toast-host">
        {items.map((t) => (
          <div key={t.id} className="toast">
            <Icon name={t.icon} size={16} />
            <span>{t.text}</span>
          </div>
        ))}
      </div>
    </ToastContext.Provider>
  );
}
const useToast = () => React.useContext(ToastContext);

/* ── Modal ───────────────────────────────────────────────────────────── */
function Modal({ open, onClose, title, children, footer, size }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className={`modal${size === 'lg' ? ' modal-lg' : ''}`} onClick={(e) => e.stopPropagation()}>
        {title && (
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '20px 24px 0' }}>
            <h2 style={{ margin: 0, fontSize: 18, fontWeight: 700 }}>{title}</h2>
            <IconButton icon="x" onClick={onClose} />
          </div>
        )}
        <div style={{ padding: 24 }}>{children}</div>
        {footer && (
          <div style={{
            padding: '16px 24px', borderTop: '1px solid var(--border-subtle)',
            display: 'flex', justifyContent: 'flex-start', gap: 8,
            background: 'var(--sand-100)', borderRadius: '0 0 var(--radius-2xl) var(--radius-2xl)',
          }}>{footer}</div>
        )}
      </div>
    </div>
  );
}

/* ── Tabs / segmented ────────────────────────────────────────────────── */
function Segmented({ value, onChange, options }) {
  return (
    <div style={{
      display: 'inline-flex', background: 'var(--surface-sunken)',
      borderRadius: 999, padding: 3, gap: 2,
    }}>
      {options.map((opt) => {
        const k = typeof opt === 'string' ? opt : opt.value;
        const label = typeof opt === 'string' ? opt : opt.label;
        const icon = typeof opt === 'object' ? opt.icon : null;
        const active = value === k;
        return (
          <button key={k} onClick={() => onChange(k)}
            style={{
              padding: '6px 14px',
              borderRadius: 999,
              border: 'none',
              background: active ? 'var(--surface-elevated)' : 'transparent',
              boxShadow: active ? 'var(--elev-1)' : 'none',
              color: active ? 'var(--text-primary)' : 'var(--text-secondary)',
              fontSize: 13, fontWeight: 600,
              display: 'inline-flex', alignItems: 'center', gap: 6,
              transition: 'all var(--dur-quick) var(--ease-standard)',
              cursor: 'pointer',
            }}>
            {icon && <Icon name={icon} size={14} />}
            {label}
          </button>
        );
      })}
    </div>
  );
}

/* ── PhotoSlot — abstract sage/coral gradient placeholder ───────────── */
function PhotoSlot({ angle = 'front', date, week, available = true, size = 'md', style, onClick }) {
  // Deterministic gradient based on angle + week so the same slot looks the same
  const seed = (angle.charCodeAt(0) + (week || 0) * 7) % 6;
  const gradients = [
    'linear-gradient(135deg, #82A695 0%, #496459 100%)',
    'linear-gradient(160deg, #EFB4A4 0%, #D5816F 100%)',
    'linear-gradient(135deg, #A8C5B8 0%, #5F8273 100%)',
    'linear-gradient(160deg, #F6CEC2 0%, #E8A598 100%)',
    'linear-gradient(135deg, #C8DBD0 0%, #82A695 100%)',
    'linear-gradient(160deg, #FBE7E0 0%, #EFB4A4 100%)',
  ];
  const dims = size === 'sm' ? { w: 96, h: 96, r: 12 } :
               size === 'lg' ? { w: 280, h: 320, r: 18 } :
               size === 'xl' ? { w: '100%', h: 360, r: 20 } :
               { w: 160, h: 180, r: 14 };
  if (!available) {
    return (
      <div style={{
        width: dims.w, height: dims.h, borderRadius: dims.r,
        border: '1.5px dashed var(--border-strong)',
        background: 'var(--surface-sunken)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexDirection: 'column', gap: 6, color: 'var(--text-tertiary)',
        ...style,
      }}>
        <Icon name="camera" size={20} />
        <span style={{ fontSize: 11, fontWeight: 600 }}>ממתינה</span>
      </div>
    );
  }
  return (
    <div onClick={onClick} style={{
      width: dims.w, height: dims.h, borderRadius: dims.r,
      background: gradients[seed],
      position: 'relative', overflow: 'hidden',
      boxShadow: 'var(--elev-2)',
      cursor: onClick ? 'pointer' : 'default',
      transition: 'transform var(--dur-standard) var(--ease-emphasized), box-shadow var(--dur-standard) var(--ease-emphasized)',
      ...style,
    }}
    onMouseEnter={(e) => onClick && (e.currentTarget.style.transform = 'translateY(-2px)')}
    onMouseLeave={(e) => onClick && (e.currentTarget.style.transform = 'none')}
    >
      {/* Soft inner glow */}
      <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(circle at 50% 35%, rgba(255,255,255,0.25), transparent 60%)' }} />
      {/* Angle + date overlay */}
      <div style={{
        position: 'absolute', top: 10, insetInlineEnd: 10,
        background: 'rgba(22,29,31,0.36)', backdropFilter: 'blur(6px)',
        color: 'white', padding: '3px 8px', borderRadius: 999,
        fontSize: 10, fontWeight: 700, letterSpacing: 0.2,
      }}>{SJ_DATA.ANGLE_LABELS[angle]}</div>
      {date && (
        <div style={{
          position: 'absolute', bottom: 10, insetInlineEnd: 10,
          background: 'rgba(22,29,31,0.36)', backdropFilter: 'blur(6px)',
          color: 'white', padding: '3px 8px', borderRadius: 999,
          fontSize: 10, fontWeight: 600, direction: 'ltr',
        }}>{date}</div>
      )}
      <div style={{
        position: 'absolute', bottom: 10, insetInlineStart: 10,
        opacity: 0.65,
      }}>
        <Icon name="camera" size={14} style={{ color: 'white' }} />
      </div>
    </div>
  );
}

/* ── Empty state ─────────────────────────────────────────────────────── */
function Empty({ icon = 'leaf', title, body, action }) {
  return (
    <div className="empty">
      <div className="empty-icon"><Icon name={icon} size={28} /></div>
      <h3>{title}</h3>
      {body && <p>{body}</p>}
      {action && <div style={{ marginTop: 8 }}>{action}</div>}
    </div>
  );
}

/* ── Page header (within content area) ───────────────────────────────── */
function PageHeader({ title, subtitle, actions }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 24, marginBottom: 28, flexWrap: 'wrap' }}>
      <div>
        <h1 style={{ margin: 0, fontSize: 30, fontWeight: 700, letterSpacing: '-0.4px', color: 'var(--text-primary)' }}>
          {title}
        </h1>
        {subtitle && <p style={{ margin: '6px 0 0', color: 'var(--text-tertiary)', fontSize: 14 }}>{subtitle}</p>}
      </div>
      {actions && <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>{actions}</div>}
    </div>
  );
}

/* ── Status dot ──────────────────────────────────────────────────────── */
function StatusDot({ kind = 'sage', size = 8 }) {
  const colors = { sage: 'var(--sage-500)', coral: 'var(--coral-500)', warn: 'var(--warning)', muted: 'var(--sand-500)' };
  return <span style={{ display: 'inline-block', width: size, height: size, borderRadius: '50%', background: colors[kind] }} />;
}

Object.assign(window, {
  Icon, Avatar, Chip, Button, IconButton, Card, KPI, Sparkline, Bars,
  Skeleton, Modal, Segmented, PhotoSlot, Empty, PageHeader, StatusDot,
  ToastHost, useToast, CountUp,
});
