// ui.jsx — Shared UI primitives

const { useState, useEffect, useRef } = React;

// ── Date utilities ────────────────────────────────────────────────────────────
const formatDateDe = (iso) => {
  if (!iso) return '';
  const s = String(iso).slice(0, 10);
  const m = s.match(/^(\d{4})-(\d{2})-(\d{2})$/);
  return m ? `${m[3]}.${m[2]}.${m[1]}` : s;
};

// ── Icons ─────────────────────────────────────────────────────────────────────
const Icon = ({ name, size = 16, color = 'currentColor' }) => {
  const icons = {
    home: <path d="M3 9.5L12 3l9 6.5V20a1 1 0 01-1 1H5a1 1 0 01-1-1V9.5z" fill="none" stroke={color} strokeWidth="1.5" strokeLinejoin="round"/>,
    search: <><circle cx="11" cy="11" r="7" fill="none" stroke={color} strokeWidth="1.5"/><path d="M16.5 16.5l4 4" stroke={color} strokeWidth="1.5" strokeLinecap="round"/></>,
    plus: <path d="M12 5v14M5 12h14" stroke={color} strokeWidth="1.5" strokeLinecap="round"/>,
    edit: <path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>,
    trash: <><polyline points="3 6 5 6 21 6" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round"/><path d="M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6" fill="none" stroke={color} strokeWidth="1.5"/><path d="M10 11v6M14 11v6M9 6V4a1 1 0 011-1h4a1 1 0 011 1v2" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round"/></>,
    book: <><path d="M4 19.5A2.5 2.5 0 016.5 17H20" fill="none" stroke={color} strokeWidth="1.5"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z" fill="none" stroke={color} strokeWidth="1.5"/></>,
    flash: <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>,
    calendar: <><rect x="3" y="4" width="18" height="18" rx="2" fill="none" stroke={color} strokeWidth="1.5"/><path d="M16 2v4M8 2v4M3 10h18" stroke={color} strokeWidth="1.5" strokeLinecap="round"/></>,
    tag: <path d="M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82z M7 7h.01" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>,
    link: <><path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/><path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></>,
    chevronDown: <path d="M6 9l6 6 6-6" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>,
    chevronRight: <path d="M9 18l6-6-6-6" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>,
    eye: <><path d="M1 12S5 4 12 4s11 8 11 8-4 8-11 8S1 12 1 12z" fill="none" stroke={color} strokeWidth="1.5"/><circle cx="12" cy="12" r="3" fill="none" stroke={color} strokeWidth="1.5"/></>,
    eyeOff: <><path d="M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round"/><path d="M1 1l22 22" stroke={color} strokeWidth="1.5" strokeLinecap="round"/></>,
    moon: <path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>,
    sun: <><circle cx="12" cy="12" r="5" fill="none" stroke={color} strokeWidth="1.5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" stroke={color} strokeWidth="1.5" strokeLinecap="round"/></>,
    logout: <><path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/><polyline points="16 17 21 12 16 7" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/><line x1="21" y1="12" x2="9" y2="12" stroke={color} strokeWidth="1.5" strokeLinecap="round"/></>,
    x: <path d="M18 6L6 18M6 6l12 12" stroke={color} strokeWidth="1.5" strokeLinecap="round"/>,
    check: <path d="M20 6L9 17l-5-5" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>,
    arrowLeft: <path d="M19 12H5M12 19l-7-7 7-7" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>,
    save: <path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z M17 21v-8H7v8 M7 3v5h8" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>,
    grid: <><rect x="3" y="3" width="7" height="7" rx="1" fill="none" stroke={color} strokeWidth="1.5"/><rect x="14" y="3" width="7" height="7" rx="1" fill="none" stroke={color} strokeWidth="1.5"/><rect x="3" y="14" width="7" height="7" rx="1" fill="none" stroke={color} strokeWidth="1.5"/><rect x="14" y="14" width="7" height="7" rx="1" fill="none" stroke={color} strokeWidth="1.5"/></>,
    list: <path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" stroke={color} strokeWidth="1.5" strokeLinecap="round"/>,
    lock: <><rect x="3" y="11" width="18" height="11" rx="2" fill="none" stroke={color} strokeWidth="1.5"/><path d="M7 11V7a5 5 0 0110 0v4" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round"/></>,
    user: <><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round"/><circle cx="12" cy="7" r="4" fill="none" stroke={color} strokeWidth="1.5"/></>,
    zap: <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>,
    info: <><circle cx="12" cy="12" r="10" fill="none" stroke={color} strokeWidth="1.5"/><path d="M12 16v-4M12 8h.01" stroke={color} strokeWidth="2" strokeLinecap="round"/></>,
    upload: <><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round"/><polyline points="17 8 12 3 7 8" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/><line x1="12" y1="3" x2="12" y2="15" stroke={color} strokeWidth="1.5" strokeLinecap="round"/></>,
    columns: <><rect x="3" y="3" width="8" height="18" rx="1" fill="none" stroke={color} strokeWidth="1.5"/><rect x="13" y="3" width="8" height="18" rx="1" fill="none" stroke={color} strokeWidth="1.5"/></>,
    sliders: <><line x1="4" y1="6"  x2="20" y2="6"  stroke={color} strokeWidth="1.5" strokeLinecap="round"/><line x1="4" y1="12" x2="20" y2="12" stroke={color} strokeWidth="1.5" strokeLinecap="round"/><line x1="4" y1="18" x2="20" y2="18" stroke={color} strokeWidth="1.5" strokeLinecap="round"/><circle cx="9"  cy="6"  r="2.2" fill="var(--sidebar-bg, #fff)" stroke={color} strokeWidth="1.5"/><circle cx="15" cy="12" r="2.2" fill="var(--sidebar-bg, #fff)" stroke={color} strokeWidth="1.5"/><circle cx="7"  cy="18" r="2.2" fill="var(--sidebar-bg, #fff)" stroke={color} strokeWidth="1.5"/></>,
    bell: <><path d="M18 8a6 6 0 00-12 0c0 7-3 9-3 9h18s-3-2-3-9" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/><path d="M13.73 21a2 2 0 01-3.46 0" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></>,
    pin: <><path d="M12 17v5" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round"/><path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z" fill="none" stroke={color} strokeWidth="1.5" strokeLinejoin="round"/></>,
    bellOff: <><path d="M13.73 21a2 2 0 01-3.46 0M18.63 13A17.89 17.89 0 0118 8M6.26 6.26A5.86 5.86 0 006 8c0 7-3 9-3 9h14M18 8a6 6 0 00-9.33-5" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/><path d="M1 1l22 22" stroke={color} strokeWidth="1.5" strokeLinecap="round"/></>,
    mail: <><rect x="3" y="5" width="18" height="14" rx="2" fill="none" stroke={color} strokeWidth="1.5"/><path d="M3 7l9 6 9-6" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ flexShrink: 0, display: 'inline-block' }}>
      {icons[name] || null}
    </svg>
  );
};

// ── Button ────────────────────────────────────────────────────────────────────
const Btn = ({ children, variant = 'primary', size = 'md', onClick, disabled, icon, style = {} }) => {
  const base = {
    display: 'inline-flex', alignItems: 'center', gap: 6,
    border: 'none', cursor: disabled ? 'not-allowed' : 'pointer',
    fontFamily: 'var(--font-sans)', fontWeight: 500,
    borderRadius: 'var(--radius)', transition: 'all 0.15s ease',
    opacity: disabled ? 0.5 : 1, whiteSpace: 'nowrap',
    ...style
  };
  const sizes = {
    sm: { padding: '5px 10px', fontSize: 12 },
    md: { padding: '8px 14px', fontSize: 13 },
    lg: { padding: '11px 20px', fontSize: 14 },
  };
  const variants = {
    primary: { background: 'var(--accent)', color: '#fff' },
    secondary: { background: 'var(--surface-2)', color: 'var(--text)', border: '1px solid var(--border)' },
    ghost: { background: 'transparent', color: 'var(--text-muted)' },
    danger: { background: 'rgba(248,113,113,0.15)', color: '#f87171', border: '1px solid rgba(248,113,113,0.3)' },
  };
  const [hover, setHover] = useState(false);
  const hoverStyles = hover && !disabled ? {
    primary: { filter: 'brightness(1.1)', transform: 'translateY(-1px)' },
    secondary: { background: 'var(--surface-hover)', transform: 'translateY(-1px)' },
    ghost: { background: 'var(--surface-2)', color: 'var(--text)' },
    danger: { background: 'rgba(248,113,113,0.25)' },
  }[variant] : {};

  return (
    <button
      onClick={!disabled ? onClick : undefined}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{ ...base, ...sizes[size], ...variants[variant], ...hoverStyles }}
    >
      {icon && <Icon name={icon} size={14} />}
      {children}
    </button>
  );
};

// ── Badge / Tag ───────────────────────────────────────────────────────────────
const TagBadge = ({ label, color }) => (
  <span style={{
    display: 'inline-flex', alignItems: 'center', gap: 4,
    padding: '2px 8px', borderRadius: 20,
    fontSize: 11, fontFamily: 'var(--font-mono)',
    background: color ? `${color}20` : 'var(--surface-2)',
    color: color || 'var(--text-muted)',
    border: `1px solid ${color ? `${color}40` : 'var(--border)'}`,
  }}>
    {label}
  </span>
);

const TypeBadge = ({ type }) => {
  const map = {
    exam: { label: 'Klassenarbeit', color: '#f87171' },
    task: { label: 'Aufgabe', color: '#60a5fa' },
    project: { label: 'Projekt', color: '#a78bfa' },
    presentation: { label: 'Präsentation', color: '#34d399' },
  };
  const t = map[type] || { label: type, color: '#9b5cf6' };
  return <TagBadge label={t.label} color={t.color} />;
};

// ── Progress Bar ──────────────────────────────────────────────────────────────
const ProgressBar = ({ value, color, height = 4, animate = true }) => {
  const [width, setWidth] = useState(0);
  useEffect(() => {
    if (animate) {
      const t = setTimeout(() => setWidth(value), 100);
      return () => clearTimeout(t);
    } else {
      setWidth(value);
    }
  }, [value, animate]);
  return (
    <div style={{ width: '100%', height, background: 'var(--surface-2)', borderRadius: 99, overflow: 'hidden' }}>
      <div style={{
        height: '100%', width: `${width}%`,
        background: color || 'var(--accent)',
        borderRadius: 99, transition: 'width 0.8s cubic-bezier(0.4,0,0.2,1)',
      }} />
    </div>
  );
};

// ── Avatar ────────────────────────────────────────────────────────────────────
const Avatar = ({ initials, size = 32 }) => (
  <div style={{
    width: size, height: size, borderRadius: '50%',
    background: 'linear-gradient(135deg, var(--accent), #6d28d9)',
    display: 'flex', alignItems: 'center', justifyContent: 'center',
    color: '#fff', fontSize: size * 0.35, fontWeight: 600,
    fontFamily: 'var(--font-sans)', flexShrink: 0,
    letterSpacing: '0.05em',
  }}>
    {initials}
  </div>
);

// ── Modal ─────────────────────────────────────────────────────────────────────
const Modal = ({ open, onClose, title, children, width = 480 }) => {
  useEffect(() => {
    const handler = (e) => e.key === 'Escape' && onClose();
    if (open) document.addEventListener('keydown', handler);
    return () => document.removeEventListener('keydown', handler);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 1000,
      background: 'rgba(0,0,0,0.72)',
      display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24,
    }} onClick={onClose}>
      <div style={{
        background: 'var(--surface)', border: '1px solid var(--border)',
        borderRadius: 12, width, maxWidth: '100%',
        maxHeight: 'calc(100vh - 48px)',
        boxShadow: '0 24px 60px rgba(0,0,0,0.5)',
        display: 'flex', flexDirection: 'column', overflow: 'hidden',
        transform: 'translateZ(0)',
      }} onClick={e => e.stopPropagation()}>
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          padding: '16px 20px', borderBottom: '1px solid var(--border)', flexShrink: 0,
        }}>
          <span style={{ fontWeight: 600, color: 'var(--text)', fontSize: 14 }}>{title}</span>
          <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text-muted)', display: 'flex' }}>
            <Icon name="x" size={18} />
          </button>
        </div>
        <div style={{
          padding: 20, overflowY: 'auto', flex: 1,
          contain: 'layout paint style',
          willChange: 'scroll-position',
        }}>{children}</div>
      </div>
    </div>
  );
};

// ── Input ─────────────────────────────────────────────────────────────────────
const Input = ({ value, onChange, placeholder, type = 'text', icon, style = {} }) => {
  const [focus, setFocus] = useState(false);
  return (
    <div style={{ position: 'relative', ...style }}>
      {icon && (
        <div style={{ position: 'absolute', left: 10, top: '50%', transform: 'translateY(-50%)', color: 'var(--text-muted)', pointerEvents: 'none' }}>
          <Icon name={icon} size={14} />
        </div>
      )}
      <input
        type={type} value={value} onChange={onChange}
        placeholder={placeholder}
        onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
        style={{
          width: '100%', boxSizing: 'border-box',
          padding: icon ? '8px 12px 8px 34px' : '8px 12px',
          background: 'var(--surface-2)', border: `1px solid ${focus ? 'var(--accent)' : 'var(--border)'}`,
          borderRadius: 'var(--radius)', color: 'var(--text)',
          fontFamily: 'var(--font-sans)', fontSize: 13,
          outline: 'none', transition: 'border-color 0.15s',
          boxShadow: focus ? '0 0 0 3px var(--accent-dim)' : 'none',
        }}
      />
    </div>
  );
};

// ── Empty State ───────────────────────────────────────────────────────────────
const EmptyState = ({ icon = 'book', title, subtitle, action }) => (
  <div style={{ textAlign: 'center', padding: '60px 20px' }}>
    <div style={{ color: 'var(--text-dim)', marginBottom: 12, display: 'flex', justifyContent: 'center' }}>
      <Icon name={icon} size={36} color="var(--text-dim)" />
    </div>
    <div style={{ color: 'var(--text-muted)', fontWeight: 600, marginBottom: 6, fontSize: 15 }}>{title}</div>
    {subtitle && <div style={{ color: 'var(--text-dim)', fontSize: 13, marginBottom: 16 }}>{subtitle}</div>}
    {action}
  </div>
);

// ── Breadcrumb ────────────────────────────────────────────────────────────────
const Breadcrumb = ({ parts }) => (
  <div style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 6 }}>
    <span style={{ color: 'var(--accent)' }}>~</span>
    {parts.map((p, i) => (
      <React.Fragment key={i}>
        {i > 0 && <span style={{ color: 'var(--text-dim)' }}>/</span>}
        <span style={{ color: i === parts.length - 1 ? 'var(--text)' : 'var(--text-muted)' }}>{p}</span>
      </React.Fragment>
    ))}
    <span style={{ color: 'var(--accent)', animation: 'blink 1s step-end infinite' }}>▋</span>
  </div>
);

// ── Toast ─────────────────────────────────────────────────────────────────────
// Globaler Subscriber-Mechanismus: window.toast(message, type) pushed eine Toast,
// ToastContainer (in App gerendert) abonniert die Updates.
const __toastListeners = new Set();
let __toastSeq = 0;
window.toast = (message, type = 'info') => {
  const t = { id: ++__toastSeq, message, type };
  __toastListeners.forEach(l => l(t));
};

const ToastContainer = () => {
  const [toasts, setToasts] = useState([]);
  useEffect(() => {
    const listener = (t) => {
      setToasts(prev => [...prev, t]);
      setTimeout(() => setToasts(prev => prev.filter(x => x.id !== t.id)), 3500);
    };
    __toastListeners.add(listener);
    return () => { __toastListeners.delete(listener); };
  }, []);

  const colorFor = (type) => ({
    success: { bg: 'rgba(74,222,128,0.12)',  border: 'rgba(74,222,128,0.4)',  fg: '#4ade80' },
    error:   { bg: 'rgba(248,113,113,0.12)', border: 'rgba(248,113,113,0.4)', fg: '#f87171' },
    info:    { bg: 'var(--accent-dim)',      border: 'var(--accent)',         fg: 'var(--accent)' },
  }[type] || { bg: 'var(--surface)', border: 'var(--border)', fg: 'var(--text)' });

  return (
    <div style={{
      position: 'fixed', bottom: 16, right: 16, zIndex: 10000,
      display: 'flex', flexDirection: 'column', gap: 8, pointerEvents: 'none',
      maxWidth: 360,
    }}>
      {toasts.map(t => {
        const c = colorFor(t.type);
        return (
          <div key={t.id} style={{
            background: c.bg, border: `1px solid ${c.border}`, color: c.fg,
            padding: '10px 14px', borderRadius: 8,
            fontFamily: 'var(--font-sans)', fontSize: 13,
            boxShadow: '0 6px 24px rgba(0,0,0,0.25)',
            pointerEvents: 'auto', backdropFilter: 'blur(6px)',
            animation: 'tb-toast-in 0.2s ease-out',
          }}>{t.message}</div>
        );
      })}
      <style>{`@keyframes tb-toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }`}</style>
    </div>
  );
};

Object.assign(window, { Icon, Btn, TagBadge, TypeBadge, ProgressBar, Avatar, Modal, Input, EmptyState, Breadcrumb, ToastContainer, formatDateDe });
