/* global React, useApp, LunaWordmark, LunaMark, UserAvatar, LunaAvatar, Icon */
const { useState, useRef, useEffect, useCallback } = React;

// ── Markdown renderer ───────────────────────────────────────────────
function mdInline(s) {
  return s
    .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
    .replace(/\*(.+?)\*/g, '<em>$1</em>')
    .replace(/`([^`]+)`/g, '<code>$1</code>');
}
function MdContent({ text }) {
  const blocks = text.split(/\n\n+/).filter(Boolean);
  return (
    <>{blocks.map((b, i) => {
      if (b.startsWith('### ')) return <h3 key={i} style={{ fontFamily:'var(--font-display)',fontSize:17,fontWeight:600,margin:'12px 0 6px',letterSpacing:'-0.01em' }}>{b.slice(4)}</h3>;
      if (b.startsWith('## ')) return <h2 key={i} style={{ fontFamily:'var(--font-display)',fontSize:20,fontWeight:600,margin:'14px 0 8px' }}>{b.slice(3)}</h2>;
      if (b.match(/^- /m)) {
        const items = b.split('\n').filter(l => l.startsWith('- ')).map(l => l.slice(2));
        return <ul key={i}>{items.map((li,j) => <li key={j} dangerouslySetInnerHTML={{ __html: mdInline(li) }} />)}</ul>;
      }
      return <p key={i} dangerouslySetInnerHTML={{ __html: mdInline(b).replace(/\n/g,'<br/>') }} />;
    })}</>
  );
}

// ── Streaming text ──────────────────────────────────────────────────
function useStream(text, active) {
  const [shown, setShown] = useState(active ? '' : text);
  const [done, setDone] = useState(!active);
  useEffect(() => {
    if (!active) { setShown(text); setDone(true); return; }
    setShown(''); setDone(false);
    let i = 0;
    const speed = Math.max(8, Math.floor(1600 / text.length));
    const iv = setInterval(() => {
      i += 5;
      if (i >= text.length) { setShown(text); setDone(true); clearInterval(iv); }
      else setShown(text.slice(0, i));
    }, speed);
    return () => clearInterval(iv);
  }, [text, active]);
  return [shown, done];
}

// ── Single message ──────────────────────────────────────────────────
function Msg({ msg, isLast }) {
  const { user } = useApp();
  const initials = (user?.name || '?').slice(0, 2).toUpperCase();

  const [shown, done] = useStream(
    msg.content,
    msg.streaming && isLast && msg.content === ''
  );
  const displayText = msg.streaming ? msg.content : shown;

  function copyText() {
    navigator.clipboard.writeText(msg.content).catch(() => {});
  }

  return (
    <div className={'msg ' + msg.role + ' fade-up'}>
      {msg.role === 'user' ? <UserAvatar size={28} initials={initials} /> : <LunaAvatar size={28} />}
      <div className="msg-body">
        <div className="msg-name">
          {msg.role === 'user' ? 'Du' : 'LuNa'}
          {msg.role === 'ai' && <span className="badge">V0.1</span>}
          {msg.time && <span className="time">{msg.time}</span>}
        </div>
        <div className="msg-content">
          {displayText
            ? <MdContent text={displayText} />
            : <span style={{ color: 'var(--ink-4)', fontStyle: 'italic' }}>Denkt nach…</span>
          }
          {msg.streaming && <span className="stream-caret" />}
        </div>
        {msg.role === 'ai' && !msg.streaming && msg.content && (
          <div className="msg-actions">
            <button className="icon-btn" title="Kopieren" onClick={copyText}><Icon.copy /></button>
            <button className="icon-btn" title="Neu generieren"><Icon.refresh /></button>
            <button className="icon-btn" title="Hilfreich"><Icon.thumb /></button>
          </div>
        )}
      </div>
    </div>
  );
}

// ── App Sidebar ─────────────────────────────────────────────────────
function AppSidebar({ onClose }) {
  const { go, chats, activeChatId, selectChat, newChat, deleteChat, user, logout } = useApp();
  const initials = (user?.name || '?').slice(0, 2).toUpperCase();
  const [hoveredId, setHoveredId] = useState(null);

  const grouped = [
    { label: 'Angeheftet', items: chats.filter(c => c.pinned) },
    { label: 'Heute', items: chats.filter(c => !c.pinned).slice(0, 3) },
    { label: 'Letzte 30 Tage', items: chats.filter(c => !c.pinned).slice(3) },
  ].filter(g => g.items.length > 0);

  return (
    <aside className="sidebar" style={{ animation: 'slide-in-left 300ms cubic-bezier(.2,.8,.2,1) both' }}>
      <div className="sidebar-head">
        <div className="brand-row">
          <LunaWordmark size={19} />
          {onClose && <button className="icon-btn" onClick={onClose} title="Schließen"><Icon.back /></button>}
        </div>
        <button className="btn-primary" onClick={() => { newChat(); if (onClose) onClose(); }}>
          <span className="label"><Icon.plus />Neuer Chat</span>
          <span className="kbd">⌘N</span>
        </button>
        <div className="search"><Icon.search /><input placeholder="Suchen…" readOnly /></div>
      </div>

      {/* Chats */}
      {grouped.length === 0 ? (
        <div style={{ padding: '24px 16px', color: 'var(--ink-4)', fontSize: 13, textAlign: 'center' }}>
          Noch keine Chats.<br />Starte einen neuen!
        </div>
      ) : grouped.map(g => (
        <React.Fragment key={g.label}>
          <div className="sidebar-section"><span>{g.label}</span></div>
          <div style={{ padding: '0 8px', display: 'flex', flexDirection: 'column', gap: 1 }}>
            {g.items.map(c => (
              <div key={c.id}
                className={'chat-item' + (c.id === activeChatId ? ' active' : '')}
                onClick={() => { selectChat(c.id); if (onClose) onClose(); }}
                onMouseEnter={() => setHoveredId(c.id)}
                onMouseLeave={() => setHoveredId(null)}
                style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                <span className="title" style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.title}</span>
                <button
                  onClick={e => { e.stopPropagation(); deleteChat(c.id); }}
                  title="Löschen"
                  style={{
                    flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
                    width: 18, height: 18, borderRadius: 4, border: 0,
                    background: 'transparent', cursor: 'pointer',
                    color: 'var(--ink-3)', fontSize: 14, lineHeight: 1, padding: 0,
                    opacity: hoveredId === c.id ? 1 : 0,
                    transition: 'opacity 120ms ease',
                  }}>×</button>
              </div>
            ))}
          </div>
        </React.Fragment>
      ))}

      <div style={{ flex: 1 }} />

      <div className="sidebar-foot">
        <UserAvatar size={30} initials={initials} />
        <div className="user-info">
          <div className="user-name">{user?.name || '—'}</div>
          <div className="user-plan">LuNa Early Access</div>
        </div>
        <button className="icon-btn" onClick={() => go('settings')} title="Einstellungen"><Icon.settings /></button>
      </div>
    </aside>
  );
}

// ── App Top Bar ─────────────────────────────────────────────────────
function AppTopBar({ geist, setGeist, sidebarOpen, setSidebarOpen, activeTier, setActiveTier }) {
  const { go, chats, activeChatId } = useApp();
  const [modelOpen, setModelOpen] = useState(false);
  const TIER_TO_MODEL = { normal: 'luna', pro: 'luna-pro', lite: 'luna-mini' };
  const activeModelId = TIER_TO_MODEL[activeTier] || 'luna';
  const models = [
    { id: 'luna',      tier: 'normal', name: 'LuNa',      desc: 'Standard · Pi' },
    { id: 'luna-pro',  tier: 'pro',    name: 'LuNa Pro',  desc: 'GPU · schnell',  tag: 'Pro' },
    { id: 'luna-mini', tier: 'lite',   name: 'LuNa Lite', desc: 'Pi · sparsam',   tag: 'Lite' },
  ];
  const cur = models.find(m => m.id === activeModelId) || models[0];
  return (
    <header className="topbar" style={{ animation: 'none' }}>
      <button className="icon-btn lg" onClick={() => setSidebarOpen(!sidebarOpen)} style={{ display: 'none' }} id="mob-menu-btn"><Icon.more /></button>
      <button className="model-picker" onClick={() => setModelOpen(!modelOpen)}>
        <span className="model-dot" />
        <span>{cur.name}</span>
        <Icon.chev />
      </button>
      <button className={'geist-toggle' + (geist ? ' on' : '')} onClick={() => setGeist(!geist)}>
        <Icon.ghost /><span>{geist ? 'Geist aktiv' : 'Geist-Modus'}</span>
      </button>
      <button className="icon-btn lg" style={{ marginLeft: 'auto' }} onClick={() => go('settings')} title="Einstellungen">
        <Icon.settings />
      </button>
      {modelOpen && (
        <div className="fade-up" style={{ position:'absolute',top:52,left:16,zIndex:20,background:'var(--bg-elevated)',border:'1px solid var(--border-strong)',borderRadius:12,padding:6,boxShadow:'var(--shadow-lg)',width:280 }} onClick={() => setModelOpen(false)}>
          <div style={{ padding:'8px 10px 4px',fontSize:10.5,fontWeight:600,letterSpacing:'0.08em',textTransform:'uppercase',color:'var(--ink-3)' }}>Modell wählen</div>
          {models.map(m => (
            <div key={m.id} onClick={() => { setActiveTier(m.tier); setModelOpen(false); }}
              style={{ display:'flex',alignItems:'center',gap:12,padding:'8px 10px',borderRadius:8,cursor:'pointer',background:m.id===activeModelId?'var(--bg-active)':'transparent' }}>
              <div style={{ width:8,height:8,borderRadius:'50%',background:m.id===activeModelId?'var(--accent)':'var(--ink-4)',flexShrink:0 }} />
              <div style={{ flex:1 }}>
                <div style={{ fontSize:13,fontWeight:500,color:'var(--ink)' }}>{m.name}</div>
                <div style={{ fontSize:11,color:'var(--ink-3)' }}>{m.desc}</div>
              </div>
              {m.tag && <span style={{ fontSize:10,padding:'2px 6px',borderRadius:4,background:'var(--bg-sunken)',color:'var(--ink-2)',fontWeight:500 }}>{m.tag}</span>}
            </div>
          ))}
        </div>
      )}
    </header>
  );
}

// ── Chat Composer ───────────────────────────────────────────────────
function ChatComposer({ geist, onSend }) {
  const [val, setVal] = useState('');
  const ref = useRef();
  useEffect(() => {
    if (ref.current) { ref.current.style.height = 'auto'; ref.current.style.height = ref.current.scrollHeight + 'px'; }
  }, [val]);
  function send() {
    const text = val.trim();
    if (!text) return;
    setVal('');
    onSend(text);
  }
  function onKey(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }
  return (
    <div className="composer-wrap">
      <div className="composer">
        <textarea ref={ref} value={val} onChange={e => setVal(e.target.value)} onKeyDown={onKey}
          placeholder={geist ? 'Geist-Modus aktiv — Chat wird nicht gespeichert…' : 'Schreib etwas an LuNa…'} rows={1} />
        <div className="composer-tools">
          <button className="tool-chip"><Icon.attach />Anhang</button>
          <button className="tool-chip"><Icon.globe />Web</button>
          <button className="icon-btn"><Icon.mic /></button>
          <button className={'send' + (val.trim() ? '' : ' disabled')} onClick={send}><Icon.send /></button>
        </div>
      </div>
      <div className="composer-foot">
        {geist ? <span className="geist-note">🌙 Geist-Modus: Chat wird nicht gespeichert.</span> : 'LuNa kann Fehler machen. Wichtige Infos prüfen.'}
      </div>
    </div>
  );
}

// ── Greeting ────────────────────────────────────────────────────────
function getGreeting(name) {
  const h = new Date().getHours();
  if (h < 5) return `Noch wach, <em>${name}</em>?`;
  if (h < 11) return `Guten Morgen, <em>${name}</em>.`;
  if (h < 14) return `Hallo <em>${name}</em>, was steht an?`;
  if (h < 18) return `Schöner Nachmittag, <em>${name}</em>.`;
  if (h < 22) return `Guten Abend, <em>${name}</em>.`;
  return `Noch wach, <em>${name}</em>?`;
}

// ── Chat Screen ─────────────────────────────────────────────────────
// ── Tier-Mapping: Modell-Picker-ID → Backend-Tier ──────────────────────────
const MODEL_TIER = { luna: 'normal', 'luna-pro': 'pro', 'luna-mini': 'lite' };

// ── WebSocket-URL (relativ zur aktuellen Seite = Pi-Server) ────────────────
function wsUrl() {
  const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
  return `${proto}//${location.host}/ws/chat`;
}

function ChatScreen() {
  const { go, chats, activeChat, activeChatId, addMessage, updateMessage, newChat, user } = useApp();
  const [geist, setGeist]     = useState(false);
  const [responding, setResponding] = useState(false);
  const [activeTier, setActiveTier] = useState('normal');
  const scrollRef = useRef();
  const [mobSidebarOpen, setMobSidebarOpen] = useState(false);
  const wsRef = useRef(null);

  const msgs = activeChat?.messages || [];

  function scrollBottom() {
    setTimeout(() => {
      if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
    }, 60);
  }

  async function handleSend(text) {
    if (responding) return;
    const now = new Date().toLocaleTimeString('de', { hour: '2-digit', minute: '2-digit' });
    const chatId = activeChatId || newChat();

    const userMsg = { id: Date.now() + 'u', role: 'user', time: now, content: text };
    addMessage(chatId, userMsg);
    setResponding(true);
    scrollBottom();

    // Platzhalter-Nachricht für Streaming
    const aiId  = Date.now() + 'a';
    const aiMsg = { id: aiId, role: 'ai', time: now, content: '', streaming: true };
    addMessage(chatId, aiMsg);
    scrollBottom();

    const history = [...msgs, userMsg].slice(-8).map(m => ({
      role:    m.role === 'user' ? 'user' : 'assistant',
      content: m.content,
    }));

    let accumulated = '';
    let ws = null;

    try {
      ws = new WebSocket(wsUrl());
      wsRef.current = ws;

      await new Promise((resolve, reject) => {
        ws.onopen = () => {
          ws.send(JSON.stringify({
            type: 'chat', messages: history, tier: activeTier,
            token: user?.token || '', chat_id: chatId,
          }));
        };

        ws.onmessage = (ev) => {
          const msg = JSON.parse(ev.data);

          if (msg.type === 'queued') {
            // Warte-Info könnte man anzeigen
          } else if (msg.type === 'token') {
            accumulated += msg.text;
            updateMessage(chatId, aiId, { content: accumulated, streaming: true });
            scrollBottom();
          } else if (msg.type === 'done') {
            updateMessage(chatId, aiId, { content: accumulated || '…', streaming: false });
            resolve();
          } else if (msg.type === 'error') {
            updateMessage(chatId, aiId, {
              content: `Fehler: ${msg.message}`,
              streaming: false,
            });
            resolve();
          }
        };

        ws.onerror = () => reject(new Error('WebSocket-Verbindung fehlgeschlagen'));
        ws.onclose = (e) => {
          if (e.code !== 1000 && !accumulated) reject(new Error('Verbindung getrennt'));
          else resolve();
        };
      });

    } catch (e) {
      updateMessage(chatId, aiId, {
        content: `Verbindungsfehler: ${e.message}\n\nLäuft der LuNa-Server auf dem Pi?`,
        streaming: false,
      });
    } finally {
      if (ws && ws.readyState < 2) ws.close();
      wsRef.current = null;
      setResponding(false);
      scrollBottom();
    }
  }

  const suggestions = [
    { label: 'Schreiben', text: 'Schreib mir eine professionelle E-Mail an einen Kunden, der eine Deadline verschoben hat.' },
    { label: 'Code', text: 'React Hook für Debounced Search — mit TypeScript-Typen.' },
    { label: 'Lernen', text: 'Erklär mir Vector Embeddings so, dass ich es meinem Schwager (Anwalt) erklären kann.' },
    { label: 'Planen', text: 'Wochenplan für Marathonvorbereitung — ich laufe aktuell 30 km/Woche.' },
  ];

  const firstName = user?.name?.split(' ')[0] || 'du';

  return (
    <Screen>
      <div className="app">
        {/* Desktop sidebar */}
        <div className="desktop-sidebar">
          <AppSidebar />
        </div>

        {/* Mobile sidebar overlay */}
        {mobSidebarOpen && (
          <div style={{ position:'fixed',inset:0,zIndex:100,display:'flex' }}>
            <div style={{ position:'absolute',inset:0,background:'rgba(0,0,0,0.4)' }} onClick={() => setMobSidebarOpen(false)} />
            <div style={{ position:'relative',zIndex:1,width:280 }}>
              <AppSidebar onClose={() => setMobSidebarOpen(false)} />
            </div>
          </div>
        )}

        <div className="main">
          <div style={{ position: 'relative' }}>
            <div style={{ display:'flex',alignItems:'center' }}>
              <button className="icon-btn mob-only" onClick={() => setMobSidebarOpen(true)} style={{ margin:'0 4px 0 12px',width:36,height:36 }}><Icon.more /></button>
              <AppTopBar geist={geist} setGeist={setGeist} sidebarOpen={mobSidebarOpen} setSidebarOpen={setMobSidebarOpen} activeTier={activeTier} setActiveTier={setActiveTier} />
            </div>
          </div>

          <div className="chat-scroll" ref={scrollRef}>
            {msgs.length === 0 ? (
              <div className="chat-empty">
                <LunaMark size={56} />
                <h1 className="greet" dangerouslySetInnerHTML={{ __html: getGreeting(firstName) }} />
                <div className="sub">Frag etwas, lade eine Datei hoch oder wähle einen Vorschlag.</div>
                <div className="suggestions stagger">
                  {suggestions.map((s, i) => (
                    <button key={i} className="suggest" onClick={() => handleSend(s.text)}>
                      <span className="label">{s.label}</span>{s.text}
                    </button>
                  ))}
                </div>
              </div>
            ) : (
              <div className="messages">
                {msgs.map((m, i) => <Msg key={m.id} msg={m} isLast={i === msgs.length - 1} />)}
                {responding && (
                  <div className="msg ai fade-up">
                    <LunaAvatar size={28} />
                    <div className="msg-body">
                      <div className="msg-name">LuNa <span className="badge">Standard</span></div>
                      <div className="msg-content" style={{ display:'flex',gap:5,alignItems:'center',paddingTop:4 }}>
                        {[0,1,2].map(j => <span key={j} style={{ width:7,height:7,borderRadius:'50%',background:'var(--ink-4)',animation:`typingB 1.2s ease ${j*0.2}s infinite`,display:'inline-block' }} />)}
                      </div>
                    </div>
                  </div>
                )}
              </div>
            )}
          </div>

          <ChatComposer geist={geist} onSend={handleSend} />
        </div>
      </div>
      <style>{`@keyframes typingB { 0%,60%,100%{transform:translateY(0);opacity:.4} 30%{transform:translateY(-5px);opacity:1} }`}</style>
    </Screen>
  );
}
window.ChatScreen = ChatScreen;

