// chat.jsx — Section-Chat-Drawer. Lädt Verlauf via REST,
// abonniert Live-Updates über window.ChatClient (WebSocket).
// Mentions [[Notiz]] und @user werden client-seitig in klickbare Links gerendert.

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

  const EDIT_WINDOW_MS = 15 * 60 * 1000;

  // Rendert einen Message-Body mit [[Note]]- und @user-Mentions als React-Knoten.
  // Note-Mentions: klickbar → setRoute. User-Mentions: nur styled (keine Profil-Seite).
  function renderBody(body, mentions, notes, currentUserId, setRoute) {
    if (!body) return null;
    const noteByTitle = new Map((mentions?.notes || []).map(n => [n.title.toLowerCase(), n]));
    const userByName  = new Map((mentions?.users || []).map(u => [u.name.toLowerCase(), u]));

    const out = [];
    let i = 0;
    const re = /(\[\[([^\]]{1,200})\]\])|((?:^|\s)@([\w.-]{1,80}))/g;
    let m;
    while ((m = re.exec(body)) !== null) {
      if (m.index > i) out.push(body.slice(i, m.index));
      if (m[1]) {
        // [[Note Title]]
        const title = m[2].trim();
        const ref = noteByTitle.get(title.toLowerCase());
        const fallbackNote = !ref ? notes.find(n => n.title?.toLowerCase() === title.toLowerCase()) : null;
        const noteId = ref?.id || fallbackNote?.id;
        out.push(
          <span key={out.length}
            onClick={(e) => { e.stopPropagation(); if (noteId) setRoute({ page: 'note', noteId }); }}
            style={{
              display: 'inline-flex', alignItems: 'center', gap: 3,
              padding: '0 6px', borderRadius: 4,
              background: noteId ? 'var(--accent-dim)' : 'rgba(248,113,113,0.12)',
              color: noteId ? 'var(--accent)' : '#f87171',
              fontSize: 'inherit', cursor: noteId ? 'pointer' : 'default',
              border: `1px solid ${noteId ? 'transparent' : 'rgba(248,113,113,0.3)'}`,
              textDecoration: 'none',
            }}
            title={noteId ? `Notiz öffnen: ${title}` : `Notiz „${title}" nicht gefunden`}
          >
            📝 {title}
          </span>
        );
      } else if (m[3]) {
        // @user — Whitespace vor @ behalten
        const leading = m[3].startsWith(' ') || m[3].startsWith('\t') || m[3].startsWith('\n') ? m[3][0] : '';
        const name = m[4];
        const ref = userByName.get(name.toLowerCase());
        const isMe = ref && currentUserId && ref.id === currentUserId;
        if (leading) out.push(leading);
        out.push(
          <span key={out.length}
            style={{
              padding: '0 5px', borderRadius: 4,
              background: isMe ? 'rgba(251,191,36,0.18)' : 'var(--surface-2)',
              color: isMe ? '#fbbf24' : 'var(--accent)',
              fontWeight: 500,
              border: `1px solid ${isMe ? 'rgba(251,191,36,0.3)' : 'var(--border)'}`,
            }}
          >
            @{name}
          </span>
        );
      }
      i = re.lastIndex;
    }
    if (i < body.length) out.push(body.slice(i));
    return out;
  }

  function formatTime(iso) {
    const d = new Date(iso);
    const now = new Date();
    const sameDay = d.toDateString() === now.toDateString();
    if (sameDay) return d.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' });
    return d.toLocaleString('de-DE', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
  }

  const ChatDrawer = ({ sectionId, sectionLabel, sectionShort, sectionColor, user, notes, setRoute, onClose, userCan = () => true }) => {
    const [messages, setMessages] = useState([]);
    const [loading, setLoading] = useState(true);
    const [loadingOlder, setLoadingOlder] = useState(false);
    const [hasMore, setHasMore] = useState(false);
    const [presence, setPresence] = useState([]);
    const [input, setInput] = useState('');
    const [sending, setSending] = useState(false);
    const [error, setError] = useState('');
    const [editingId, setEditingId] = useState(null);
    const [editingBody, setEditingBody] = useState('');

    const listRef = useRef(null);
    const bottomRef = useRef(null);
    const inputRef = useRef(null);

    const canWrite = userCan('chat:write');
    const canModerate = userCan('chat:moderate') || user?.role === 'admin';

    // Initial-Load
    useEffect(() => {
      let cancelled = false;
      (async () => {
        setLoading(true); setError('');
        const { ok, data } = await apiFetch(`/api/chat/${sectionId}`);
        if (cancelled) return;
        if (!ok) {
          setError(data?.error || 'Verlauf konnte nicht geladen werden.');
          setLoading(false);
          return;
        }
        setMessages(data.messages || []);
        setHasMore(!!data.hasMore);
        setLoading(false);
        // ans Ende scrollen
        setTimeout(() => bottomRef.current?.scrollIntoView({ block: 'end' }), 50);
      })();
      return () => { cancelled = true; };
    }, [sectionId]);

    // Subscribe + Live-Updates
    useEffect(() => {
      if (!window.ChatClient) return;
      window.ChatClient.subscribe(sectionId);

      const offMsg = window.ChatClient.on('message', (evt) => {
        if (evt.sectionId !== sectionId) return;
        setMessages(prev => prev.some(m => m.id === evt.message.id) ? prev : [...prev, evt.message]);
        setTimeout(() => bottomRef.current?.scrollIntoView({ block: 'end', behavior: 'smooth' }), 30);
      });
      const offEdit = window.ChatClient.on('message-edited', (evt) => {
        if (evt.sectionId !== sectionId) return;
        setMessages(prev => prev.map(m => m.id === evt.message.id ? evt.message : m));
      });
      const offDel = window.ChatClient.on('message-deleted', (evt) => {
        if (evt.sectionId !== sectionId) return;
        setMessages(prev => prev.map(m => m.id === evt.messageId ? { ...m, body: '', deletedAt: new Date().toISOString() } : m));
      });
      const offPresence = window.ChatClient.on('presence', (evt) => {
        if (evt.sectionId !== sectionId) return;
        setPresence(evt.users || []);
      });

      return () => {
        offMsg(); offEdit(); offDel(); offPresence();
        if (window.ChatClient.currentSection === sectionId) {
          window.ChatClient.unsubscribe();
        }
      };
    }, [sectionId]);

    const loadOlder = async () => {
      if (loadingOlder || !hasMore || messages.length === 0) return;
      setLoadingOlder(true);
      const oldest = messages[0];
      const list = listRef.current;
      const prevScrollHeight = list?.scrollHeight || 0;
      const { ok, data } = await apiFetch(`/api/chat/${sectionId}?before=${oldest.id}`);
      if (ok) {
        setMessages(prev => [...(data.messages || []), ...prev]);
        setHasMore(!!data.hasMore);
        // Scroll-Position relativ stabil halten
        setTimeout(() => {
          if (list) list.scrollTop = list.scrollHeight - prevScrollHeight;
        }, 0);
      }
      setLoadingOlder(false);
    };

    const handleSend = async () => {
      const body = input.trim();
      if (!body || sending) return;
      setSending(true); setError('');
      const { ok, data } = await apiFetch(`/api/chat/${sectionId}`, {
        method: 'POST', body: { body },
      });
      setSending(false);
      if (!ok) {
        setError(data?.error || 'Senden fehlgeschlagen.');
        return;
      }
      setInput('');
      // Optimistic insert (falls WS-Echo schneller war, dedupe via id-Check)
      setMessages(prev => prev.some(m => m.id === data.message.id) ? prev : [...prev, data.message]);
      setTimeout(() => bottomRef.current?.scrollIntoView({ block: 'end', behavior: 'smooth' }), 30);
    };

    const handleKeyDown = (e) => {
      // Enter sendet, Shift+Enter macht Zeilenumbruch
      if (e.key === 'Enter' && !e.shiftKey) {
        e.preventDefault();
        if (editingId) saveEdit(); else handleSend();
      } else if (e.key === 'Escape' && editingId) {
        cancelEdit();
      }
    };

    const startEdit = (m) => {
      setEditingId(m.id);
      setEditingBody(m.body);
      setTimeout(() => inputRef.current?.focus(), 30);
    };
    const cancelEdit = () => {
      setEditingId(null); setEditingBody('');
    };
    const saveEdit = async () => {
      const body = editingBody.trim();
      if (!body || !editingId) return cancelEdit();
      const { ok, data } = await apiFetch(`/api/chat/messages/${editingId}`, {
        method: 'PATCH', body: { body },
      });
      if (!ok) { setError(data?.error || 'Edit fehlgeschlagen.'); return; }
      setMessages(prev => prev.map(m => m.id === editingId ? data.message : m));
      cancelEdit();
    };

    const deleteMessage = async (id) => {
      if (!confirm('Nachricht löschen?')) return;
      const { ok, data, status } = await apiFetch(`/api/chat/messages/${id}`, { method: 'DELETE' });
      if (!ok && status !== 204) { setError(data?.error || 'Löschen fehlgeschlagen.'); return; }
      setMessages(prev => prev.map(m => m.id === id ? { ...m, body: '', deletedAt: new Date().toISOString() } : m));
    };

    const canEditMsg = (m) => {
      if (!m || m.deletedAt) return false;
      if (m.authorId !== user.id) return false;
      return Date.now() - new Date(m.createdAt).getTime() < EDIT_WINDOW_MS;
    };
    const canDeleteMsg = (m) => {
      if (!m || m.deletedAt) return false;
      return m.authorId === user.id || canModerate;
    };

    return (
      <div style={{
        position: 'fixed', top: 0, right: 0, height: '100vh', width: 380,
        background: 'var(--surface)', borderLeft: '1px solid var(--border)',
        boxShadow: '-12px 0 32px rgba(0,0,0,0.3)',
        display: 'flex', flexDirection: 'column',
        zIndex: 900, animation: 'slideInRight 0.18s ease',
      }}>
        {/* Header */}
        <div style={{
          padding: '14px 16px', borderBottom: '1px solid var(--border)',
          display: 'flex', flexDirection: 'column', gap: 8, flexShrink: 0,
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ width: 8, height: 8, borderRadius: '50%', background: sectionColor || 'var(--accent)' }} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                {sectionShort || 'Chat'}
              </div>
              <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                {sectionLabel || 'Chat'}
              </div>
            </div>
            <button onClick={onClose}
              title="Chat schließen"
              style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text-muted)', padding: 4, borderRadius: 4, display: 'flex' }}
              onMouseEnter={e => e.currentTarget.style.color = 'var(--text)'}
              onMouseLeave={e => e.currentTarget.style.color = 'var(--text-muted)'}
            >
              <Icon name="x" size={18} />
            </button>
          </div>

          {/* Online-Presence */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap', minHeight: 22 }}>
            <span style={{ fontSize: 10, color: 'var(--text-muted)', fontFamily: 'var(--font-mono)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>
              Online · {presence.length}
            </span>
            {presence.slice(0, 8).map(u => (
              <span key={u.id} title={u.name + (u.id === user.id ? ' (du)' : '')}
                style={{
                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                  width: 22, height: 22, borderRadius: '50%',
                  background: u.id === user.id ? 'var(--accent)' : 'var(--surface-2)',
                  color: u.id === user.id ? '#fff' : 'var(--text)',
                  fontSize: 9, fontFamily: 'var(--font-mono)', fontWeight: 600,
                  border: '2px solid var(--surface)',
                  marginLeft: -4,
                }}
              >
                {u.initials}
              </span>
            ))}
            {presence.length > 8 && (
              <span style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>+{presence.length - 8}</span>
            )}
          </div>
        </div>

        {/* Messages */}
        <div ref={listRef} style={{
          flex: 1, overflowY: 'auto', padding: '10px 14px',
          display: 'flex', flexDirection: 'column', gap: 8,
        }}>
          {loading && <div style={{ textAlign: 'center', color: 'var(--text-muted)', fontSize: 12, padding: 20 }}>Lade Verlauf…</div>}
          {!loading && hasMore && (
            <button onClick={loadOlder} disabled={loadingOlder}
              style={{ background: 'transparent', border: '1px solid var(--border)', borderRadius: 6, padding: '4px 10px', color: 'var(--text-muted)', fontSize: 11, cursor: 'pointer', fontFamily: 'var(--font-mono)' }}>
              {loadingOlder ? '…' : 'Älteres laden'}
            </button>
          )}
          {!loading && messages.length === 0 && (
            <div style={{ textAlign: 'center', color: 'var(--text-dim)', fontSize: 12, padding: 30 }}>
              Noch keine Nachrichten. Schreib die erste.
            </div>
          )}
          {messages.map((m, idx) => {
            const isMine = m.authorId === user.id;
            const isDeleted = !!m.deletedAt;
            const prev = messages[idx - 1];
            const sameAuthor = prev && prev.authorId === m.authorId && !isDeleted && !prev.deletedAt
              && (new Date(m.createdAt) - new Date(prev.createdAt) < 5 * 60 * 1000);
            return (
              <div key={m.id} style={{
                display: 'flex', flexDirection: 'column', gap: 2,
                marginTop: sameAuthor ? 0 : 6,
              }}>
                {!sameAuthor && !isDeleted && (
                  <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
                    <span style={{ fontSize: 12, fontWeight: 600, color: isMine ? 'var(--accent)' : 'var(--text)' }}>
                      {m.authorName || '[gelöschter User]'}
                    </span>
                    <span style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)' }}>
                      {formatTime(m.createdAt)}
                      {m.editedAt && <span title={`bearbeitet ${formatTime(m.editedAt)}`}> · bearb.</span>}
                    </span>
                  </div>
                )}
                {editingId === m.id ? (
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                    <textarea
                      value={editingBody}
                      onChange={e => setEditingBody(e.target.value)}
                      onKeyDown={handleKeyDown}
                      autoFocus
                      style={{
                        background: 'var(--surface-2)', border: '1px solid var(--accent)', borderRadius: 6,
                        color: 'var(--text)', fontSize: 13, padding: 8, fontFamily: 'inherit',
                        resize: 'vertical', minHeight: 40, outline: 'none',
                      }}
                    />
                    <div style={{ display: 'flex', gap: 6, fontSize: 11, color: 'var(--text-muted)' }}>
                      <span>Enter speichern · Esc abbrechen</span>
                      <div style={{ flex: 1 }} />
                      <button onClick={cancelEdit} style={{ background: 'none', border: 'none', color: 'var(--text-muted)', cursor: 'pointer', fontSize: 11 }}>Abbrechen</button>
                      <button onClick={saveEdit} style={{ background: 'var(--accent)', border: 'none', color: '#fff', borderRadius: 4, padding: '2px 8px', cursor: 'pointer', fontSize: 11 }}>Speichern</button>
                    </div>
                  </div>
                ) : (
                  <div className="chat-row" style={{
                    fontSize: 13, color: isDeleted ? 'var(--text-dim)' : 'var(--text)',
                    fontStyle: isDeleted ? 'italic' : 'normal',
                    lineHeight: 1.5, wordBreak: 'break-word', whiteSpace: 'pre-wrap',
                    paddingRight: 28, position: 'relative',
                  }}>
                    {isDeleted ? '[Nachricht gelöscht]' : renderBody(m.body, m.mentions, notes || [], user.id, setRoute)}
                    {!isDeleted && (canEditMsg(m) || canDeleteMsg(m)) && (
                      <span className="chat-row-actions" style={{
                        position: 'absolute', right: 0, top: 0,
                        display: 'flex', gap: 2, opacity: 0,
                        transition: 'opacity 0.15s',
                      }}>
                        {canEditMsg(m) && (
                          <button onClick={() => startEdit(m)} title="Bearbeiten"
                            style={{ background: 'var(--surface-2)', border: '1px solid var(--border)', borderRadius: 4, padding: 3, color: 'var(--text-muted)', cursor: 'pointer', display: 'flex' }}>
                            <Icon name="edit" size={11} />
                          </button>
                        )}
                        {canDeleteMsg(m) && (
                          <button onClick={() => deleteMessage(m.id)} title="Löschen"
                            style={{ background: 'var(--surface-2)', border: '1px solid var(--border)', borderRadius: 4, padding: 3, color: '#f87171', cursor: 'pointer', display: 'flex' }}>
                            <Icon name="trash" size={11} />
                          </button>
                        )}
                      </span>
                    )}
                  </div>
                )}
              </div>
            );
          })}
          <div ref={bottomRef} />
        </div>

        {/* Input */}
        {canWrite ? (
          <div style={{ padding: 10, borderTop: '1px solid var(--border)', flexShrink: 0 }}>
            {error && <div style={{ fontSize: 11, color: '#f87171', marginBottom: 6 }}>{error}</div>}
            <div style={{ display: 'flex', gap: 6, alignItems: 'flex-end' }}>
              <textarea
                ref={inputRef}
                value={editingId ? editingBody : input}
                onChange={e => editingId ? setEditingBody(e.target.value) : setInput(e.target.value)}
                onKeyDown={handleKeyDown}
                placeholder={editingId ? 'Nachricht bearbeiten…' : `Nachricht in ${sectionShort || sectionLabel}…  ([[Notiz]] · @user)`}
                rows={2}
                style={{
                  flex: 1, background: 'var(--surface-2)', border: '1px solid var(--border)',
                  borderRadius: 8, color: 'var(--text)', fontSize: 13, padding: 8,
                  fontFamily: 'inherit', resize: 'none', outline: 'none', minHeight: 36, maxHeight: 140,
                }}
                onFocus={e => e.currentTarget.style.borderColor = 'var(--accent)'}
                onBlur={e => e.currentTarget.style.borderColor = 'var(--border)'}
              />
              <button
                onClick={editingId ? saveEdit : handleSend}
                disabled={(editingId ? !editingBody.trim() : !input.trim()) || sending}
                title={editingId ? 'Speichern (Enter)' : 'Senden (Enter)'}
                style={{
                  background: 'var(--accent)', border: 'none', borderRadius: 8,
                  color: '#fff', cursor: 'pointer', padding: '8px 12px',
                  display: 'flex', alignItems: 'center',
                  opacity: (editingId ? !editingBody.trim() : !input.trim()) || sending ? 0.5 : 1,
                }}
              >
                <Icon name="check" size={14} color="#fff" />
              </button>
            </div>
            <div style={{ fontSize: 10, color: 'var(--text-dim)', marginTop: 4, fontFamily: 'var(--font-mono)' }}>
              Enter senden · Shift+Enter Zeilenumbruch
            </div>
          </div>
        ) : (
          <div style={{ padding: 12, borderTop: '1px solid var(--border)', fontSize: 11, color: 'var(--text-muted)', textAlign: 'center' }}>
            Du hast keine Schreibrechte (chat:write fehlt).
          </div>
        )}
      </div>
    );
  };

  // Hover-Action-Buttons sichtbar machen (CSS muss ergänzt werden, ein <style>)
  if (typeof document !== 'undefined' && !document.getElementById('chat-shared-style')) {
    const el = document.createElement('style');
    el.id = 'chat-shared-style';
    el.textContent = `
      @keyframes slideInRight { from { transform: translateX(100%); } to { transform: translateX(0); } }
      .chat-row:hover .chat-row-actions { opacity: 1 !important; }
    `;
    document.head.appendChild(el);
  }

  Object.assign(window, { ChatDrawer });
})();
