import * as DocumentPicker from 'expo-document-picker';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
  ActivityIndicator,
  Alert,
  FlatList,
  KeyboardAvoidingView,
  Modal,
  Platform,
  Pressable,
  RefreshControl,
  ScrollView,
  StyleSheet,
  Text,
  TextInput,
  View,
} from 'react-native';

import {
  createMatrixRoom,
  deleteMatrixMessage,
  editMatrixMessage,
  fetchMatrixIdentity,
  fetchMatrixMembers,
  fetchMatrixMessages,
  fetchMatrixRooms,
  fetchMatrixStatus,
  fetchMatrixUsers,
  inviteMatrixMember,
  markMatrixRoomRead,
  MatrixMember,
  MatrixMessage,
  MatrixRoom,
  MatrixStatus,
  MatrixUser,
  provisionMatrixRoom,
  provisionMatrixUser,
  reactToMatrixMessage,
  removeMatrixMember,
  sendMatrixMessage,
  syncMatrixMembers,
  syncMatrixRoom,
  uploadMatrixAttachment,
} from '@/src/lib/api';
import { useAuth } from '@/src/providers/auth-provider';

const PRIMARY = '#69c350';
const REACTION_PRESETS = ['👍', '✅', '👀', '🙏'];

type DialogMode = 'create-room' | 'edit-message' | 'invite-member' | null;

function normalizeRoomKey(value: string): string {
  return value
    .trim()
    .toLowerCase()
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/[^a-z0-9_-]+/g, '-')
    .replace(/^-+|-+$/g, '')
    .slice(0, 48);
}

function messageTime(value: MatrixMessage['timestamp']): string {
  if (!value) return '';
  const date = typeof value === 'number' ? new Date(value) : new Date(value);
  if (Number.isNaN(date.getTime())) return '';
  return date.toLocaleString('de-DE', {
    day: '2-digit',
    month: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function messagePreview(message: MatrixMessage): string {
  return message.body || message.attachment?.fileName || 'Nachricht';
}

function sortMessages(messages: MatrixMessage[]): MatrixMessage[] {
  return [...messages].sort((a, b) => {
    const left = a.timestamp ? new Date(a.timestamp).getTime() : 0;
    const right = b.timestamp ? new Date(b.timestamp).getTime() : 0;
    return left - right;
  });
}

function mergeMessages(current: MatrixMessage[], incoming: MatrixMessage[]): MatrixMessage[] {
  const byId = new Map<string, MatrixMessage>();
  for (const message of current) byId.set(message.id, message);
  for (const message of incoming || []) byId.set(message.id, { ...byId.get(message.id), ...message });
  return sortMessages(Array.from(byId.values()));
}

function applyReplacements(current: MatrixMessage[], replacements: MatrixMessage[] = []): MatrixMessage[] {
  if (!replacements.length) return current;
  const byTarget = new Map<string, MatrixMessage>();
  for (const replacement of replacements) {
    const targetId = String(replacement.targetEventId || replacement.replyToEventId || replacement.id || '');
    if (targetId) byTarget.set(targetId, replacement);
  }

  return current.map((message) => {
    const replacement = byTarget.get(message.id);
    if (!replacement) return message;
    return {
      ...message,
      body: replacement.body ?? message.body,
      edited: true,
      timestamp: replacement.timestamp || message.timestamp,
    };
  });
}

function applyRedactions(
  current: MatrixMessage[],
  redactions: { redacts?: string; eventId?: string; targetEventId?: string }[] = []
): MatrixMessage[] {
  if (!redactions.length) return current;
  const ids = new Set(redactions.map((item) => item.redacts || item.eventId || item.targetEventId).filter(Boolean));
  return current.filter((message) => !ids.has(message.id));
}

function applyReactions(
  current: MatrixMessage[],
  reactions: { targetEventId?: string; key: string; count?: number; own?: boolean; senders?: string[] }[] = []
): MatrixMessage[] {
  if (!reactions.length) return current;
  return current.map((message) => {
    const next = reactions.filter((reaction) => reaction.targetEventId === message.id);
    if (!next.length) return message;
    return { ...message, reactions: next };
  });
}

export default function CommunicationScreen() {
  const { token } = useAuth();
  const messageListRef = useRef<FlatList<MatrixMessage>>(null);
  const [status, setStatus] = useState<MatrixStatus | null>(null);
  const [matrixUserId, setMatrixUserId] = useState('');
  const [rooms, setRooms] = useState<MatrixRoom[]>([]);
  const [members, setMembers] = useState<MatrixMember[]>([]);
  const [users, setUsers] = useState<MatrixUser[]>([]);
  const [messages, setMessages] = useState<MatrixMessage[]>([]);
  const [activeRoomKey, setActiveRoomKey] = useState('allgemein');
  const [syncSince, setSyncSince] = useState<string | undefined>();
  const [draft, setDraft] = useState('');
  const [search, setSearch] = useState('');
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
  const [refreshing, setRefreshing] = useState(false);
  const [sending, setSending] = useState(false);
  const [provisioning, setProvisioning] = useState(false);
  const [membersOpen, setMembersOpen] = useState(false);
  const [replyTarget, setReplyTarget] = useState<MatrixMessage | null>(null);
  const [editingMessage, setEditingMessage] = useState<MatrixMessage | null>(null);
  const [dialogMode, setDialogMode] = useState<DialogMode>(null);
  const [roomName, setRoomName] = useState('');
  const [roomTopic, setRoomTopic] = useState('');
  const [roomKey, setRoomKey] = useState('');
  const [dialogText, setDialogText] = useState('');
  const [selectedUserId, setSelectedUserId] = useState('');

  const activeRoom = useMemo(
    () => rooms.find((room) => room.key === activeRoomKey) || rooms[0] || null,
    [activeRoomKey, rooms]
  );

  const visibleRooms = useMemo(() => {
    const query = search.trim().toLowerCase();
    const base = [...rooms].sort((a, b) => {
      const groupCompare = String(a.group || '').localeCompare(String(b.group || ''));
      if (groupCompare !== 0) return groupCompare;
      return String(a.name || a.key).localeCompare(String(b.name || b.key));
    });
    if (!query) return base;
    return base.filter((room) =>
      [room.name, room.key, room.topic, room.email, room.projectNumber]
        .filter(Boolean)
        .some((value) => String(value).toLowerCase().includes(query))
    );
  }, [rooms, search]);

  const inviteCandidates = useMemo(() => {
    const existing = new Set(members.map((member) => member.matrixUserId));
    return users.filter((user) => !existing.has(user.matrixUserId));
  }, [members, users]);

  const clearRoomUnread = useCallback((roomKey: string) => {
    setRooms((current) =>
      current.map((room) => (room.key === roomKey ? { ...room, unread: 0, mentions: 0 } : room))
    );
  }, []);

  const loadRooms = useCallback(async () => {
    if (!token) return;
    const [nextStatus, identity, nextRooms, nextUsers] = await Promise.all([
      fetchMatrixStatus(token),
      fetchMatrixIdentity(token),
      fetchMatrixRooms(token),
      fetchMatrixUsers(token),
    ]);
    setStatus(nextStatus);
    setMatrixUserId(identity.matrixUserId || '');
    setRooms(nextRooms);

    if (!nextRooms.some((room) => room.key === activeRoomKey) && nextRooms[0]) {
      setActiveRoomKey(nextRooms[0].key);
    }

    setUsers(nextUsers);
  }, [activeRoomKey, token]);

  const loadRoomContent = useCallback(
    async (roomKeyToLoad: string, showSpinner = true) => {
      if (!token || !roomKeyToLoad) return;
      if (showSpinner) setLoading(true);
      setError(null);

      try {
        const [nextMessages, nextMembers, sync] = await Promise.all([
          fetchMatrixMessages(token, roomKeyToLoad),
          fetchMatrixMembers(token, roomKeyToLoad),
          syncMatrixRoom(token, roomKeyToLoad, undefined, true),
        ]);
        const merged = mergeMessages(nextMessages, sync.messages || []);
        setMessages(sortMessages(merged));
        setMembers(sync.members || nextMembers);
        setSyncSince(sync.nextBatch);
        const last = merged.at(-1);
        if (last?.id) {
          await markMatrixRoomRead(token, roomKeyToLoad, last.id);
          clearRoomUnread(roomKeyToLoad);
        }
        requestAnimationFrame(() => messageListRef.current?.scrollToEnd({ animated: true }));
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Kommunikation konnte nicht geladen werden.');
      } finally {
        setLoading(false);
        setRefreshing(false);
      }
    },
    [clearRoomUnread, token]
  );

  const refreshAll = useCallback(
    async (showSpinner = true) => {
      if (!token) return;
      if (showSpinner) setLoading(true);
      setError(null);

      try {
        await loadRooms();
        await loadRoomContent(activeRoomKey, false);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Matrix-Kommunikation konnte nicht geladen werden.');
        setLoading(false);
        setRefreshing(false);
      }
    },
    [activeRoomKey, loadRoomContent, loadRooms, token]
  );

  const pollSync = useCallback(async () => {
    if (!token || !activeRoom?.exists || !syncSince) return;
    try {
      const sync = await syncMatrixRoom(token, activeRoom.key, syncSince);
      const incomingMessages = sync.messages || [];
      setSyncSince(sync.nextBatch || syncSince);
      setMembers((current) => sync.members || current);
      setMessages((current) => {
        let next = mergeMessages(current, incomingMessages);
        next = applyReplacements(next, sync.replacements);
        next = applyReactions(next, sync.reactions);
        next = applyRedactions(next, sync.redactions);
        return next;
      });
      const last = incomingMessages.at(-1);
      if (last?.id) {
        await markMatrixRoomRead(token, activeRoom.key, last.id);
        clearRoomUnread(activeRoom.key);
      }
    } catch {
      // Polling errors are surfaced by manual refresh to avoid noisy chat usage.
    }
  }, [activeRoom, clearRoomUnread, syncSince, token]);

  useEffect(() => {
    void refreshAll(true);
  }, [refreshAll]);

  useEffect(() => {
    if (!activeRoomKey) return;
    setReplyTarget(null);
    setEditingMessage(null);
    setMessages([]);
    setMembers([]);
    setSyncSince(undefined);
    void loadRoomContent(activeRoomKey, true);
  }, [activeRoomKey, loadRoomContent]);

  useEffect(() => {
    const id = setInterval(() => void pollSync(), 5000);
    return () => clearInterval(id);
  }, [pollSync]);

  async function ensureActiveRoom(): Promise<MatrixRoom | null> {
    if (!token || !activeRoom) return null;
    if (activeRoom.exists) return activeRoom;

    setProvisioning(true);
    try {
      const room = await provisionMatrixRoom(token, activeRoom);
      setRooms((current) => current.map((item) => (item.key === activeRoom.key ? { ...item, ...room, exists: true } : item)));
      await loadRoomContent(activeRoom.key, false);
      return { ...activeRoom, ...room, exists: true };
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Raum konnte nicht bereitgestellt werden.');
      return null;
    } finally {
      setProvisioning(false);
    }
  }

  async function sendMessage() {
    if (!token || !draft.trim()) return;
    const room = await ensureActiveRoom();
    if (!room) return;

    setSending(true);
    try {
      const message = editingMessage
        ? await editMatrixMessage(token, room.key, editingMessage.id, draft.trim())
        : await sendMatrixMessage(token, room.key, draft.trim(), replyTarget?.id);
      setMessages((current) =>
        editingMessage
          ? current.map((item) => (item.id === editingMessage.id ? { ...item, ...message, edited: true } : item))
          : mergeMessages(current, [message])
      );
      setDraft('');
      setReplyTarget(null);
      setEditingMessage(null);
      requestAnimationFrame(() => messageListRef.current?.scrollToEnd({ animated: true }));
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Nachricht konnte nicht gesendet werden.');
    } finally {
      setSending(false);
    }
  }

  async function pickAttachment() {
    if (!token) return;
    const room = await ensureActiveRoom();
    if (!room) return;

    const result = await DocumentPicker.getDocumentAsync({ copyToCacheDirectory: true, multiple: false });
    if (result.canceled || !result.assets[0]) return;

    setSending(true);
    try {
      const asset = result.assets[0];
      const message = await uploadMatrixAttachment(token, room.key, {
        uri: asset.uri,
        name: asset.name || 'Anhang',
        mimeType: asset.mimeType,
      });
      setMessages((current) => mergeMessages(current, [message]));
      requestAnimationFrame(() => messageListRef.current?.scrollToEnd({ animated: true }));
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Anhang konnte nicht hochgeladen werden.');
    } finally {
      setSending(false);
    }
  }

  async function provisionUser() {
    if (!token) return;
    setProvisioning(true);
    try {
      const identity = await provisionMatrixUser(token);
      setMatrixUserId(identity.matrixUserId || '');
      await refreshAll(false);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Matrix-Benutzer konnte nicht erstellt werden.');
    } finally {
      setProvisioning(false);
    }
  }

  async function createRoomFromDialog() {
    if (!token || !roomName.trim()) return;
    const key = roomKey.trim() || normalizeRoomKey(roomName);
    if (!key) return;

    setProvisioning(true);
    try {
      const room = await createMatrixRoom(token, {
        key,
        name: roomName.trim(),
        topic: roomTopic.trim() || null,
        type: 'room',
      });
      setRooms((current) => [{ ...room, group: 'Räume', exists: true }, ...current.filter((item) => item.key !== key)]);
      setActiveRoomKey(key);
      setDialogMode(null);
      setRoomName('');
      setRoomTopic('');
      setRoomKey('');
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Raum konnte nicht erstellt werden.');
    } finally {
      setProvisioning(false);
    }
  }

  async function inviteSelectedUser() {
    if (!token || !activeRoom || !selectedUserId) return;
    const room = await ensureActiveRoom();
    if (!room) return;

    setProvisioning(true);
    try {
      await inviteMatrixMember(token, room.key, selectedUserId);
      setMembers(await fetchMatrixMembers(token, room.key));
      setDialogMode(null);
      setSelectedUserId('');
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Mitglied konnte nicht eingeladen werden.');
    } finally {
      setProvisioning(false);
    }
  }

  function openEdit(message: MatrixMessage) {
    setEditingMessage(message);
    setDialogText(message.body || '');
    setDialogMode('edit-message');
  }

  function confirmDelete(message: MatrixMessage) {
    Alert.alert('Nachricht löschen', 'Diese Nachricht wirklich entfernen?', [
      { text: 'Abbrechen', style: 'cancel' },
      {
        text: 'Löschen',
        style: 'destructive',
        onPress: () => {
          if (!token || !activeRoom) return;
          void deleteMatrixMessage(token, activeRoom.key, message.id)
            .then(() => setMessages((current) => current.filter((item) => item.id !== message.id)))
            .catch((err) => setError(err instanceof Error ? err.message : 'Nachricht konnte nicht gelöscht werden.'));
        },
      },
    ]);
  }

  function confirmRemoveMember(member: MatrixMember) {
    Alert.alert('Mitglied entfernen', `${member.displayName || member.matrixUserId} aus dem Raum entfernen?`, [
      { text: 'Abbrechen', style: 'cancel' },
      {
        text: 'Entfernen',
        style: 'destructive',
        onPress: () => {
          if (!token || !activeRoom) return;
          void removeMatrixMember(token, activeRoom.key, member.matrixUserId)
            .then(() => setMembers((current) => current.filter((item) => item.matrixUserId !== member.matrixUserId)))
            .catch((err) => setError(err instanceof Error ? err.message : 'Mitglied konnte nicht entfernt werden.'));
        },
      },
    ]);
  }

  async function addReaction(message: MatrixMessage, key: string) {
    if (!token || !activeRoom) return;
    try {
      await reactToMatrixMessage(token, activeRoom.key, message.id, key);
      await pollSync();
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Reaktion konnte nicht gesendet werden.');
    }
  }

  async function syncMembersNow() {
    if (!token || !activeRoom) return;
    setProvisioning(true);
    try {
      await syncMatrixMembers(token, activeRoom.key);
      setMembers(await fetchMatrixMembers(token, activeRoom.key));
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Mitglieder konnten nicht synchronisiert werden.');
    } finally {
      setProvisioning(false);
    }
  }

  function renderRoom({ item }: { item: MatrixRoom }) {
    const active = item.key === activeRoomKey;
    return (
      <Pressable style={[styles.roomChip, active && styles.roomChipActive]} onPress={() => setActiveRoomKey(item.key)}>
        <Text style={[styles.roomGroup, active && styles.roomTextActive]}>{item.group || 'Raum'}</Text>
        <Text style={[styles.roomName, active && styles.roomTextActive]} numberOfLines={1}>
          {item.name || item.key}
        </Text>
        <View style={styles.roomMetaRow}>
          {!item.exists ? <Text style={styles.roomBadgeMuted}>bereitstellen</Text> : null}
          {item.unread ? <Text style={styles.roomBadge}>{item.mentions ? `@${item.mentions}` : item.unread}</Text> : null}
        </View>
      </Pressable>
    );
  }

  function renderMessage({ item }: { item: MatrixMessage }) {
    const own = Boolean(item.own || item.sender === matrixUserId);
    const reply = item.replyToEventId ? messages.find((message) => message.id === item.replyToEventId) : null;

    return (
      <View style={[styles.messageRow, own && styles.messageRowOwn]}>
        <View style={[styles.messageBubble, own && styles.messageBubbleOwn]}>
          <View style={styles.messageHeader}>
            <Text style={[styles.messageSender, own && styles.messageSenderOwn]} numberOfLines={1}>
              {own ? 'Du' : item.senderDisplayName || item.sender}
            </Text>
            <Text style={[styles.messageTime, own && styles.messageTimeOwn]}>{messageTime(item.timestamp)}</Text>
          </View>
          {reply ? (
            <View style={[styles.replyBox, own && styles.replyBoxOwn]}>
              <Text style={[styles.replyText, own && styles.replyTextOwn]} numberOfLines={2}>
                {reply.senderDisplayName || reply.sender}: {messagePreview(reply)}
              </Text>
            </View>
          ) : null}
          {item.body ? <Text style={[styles.messageBody, own && styles.messageBodyOwn]}>{item.body}</Text> : null}
          {item.attachment ? (
            <View style={[styles.attachmentBox, own && styles.attachmentBoxOwn]}>
              <Text style={[styles.attachmentTitle, own && styles.messageBodyOwn]} numberOfLines={1}>
                {item.attachment.fileName || 'Anhang'}
              </Text>
              <Text style={[styles.attachmentMeta, own && styles.messageTimeOwn]}>
                {item.attachment.mimeType || 'Datei'} {item.attachment.size ? `· ${Math.round(item.attachment.size / 1024)} KB` : ''}
              </Text>
            </View>
          ) : null}
          {item.edited ? <Text style={[styles.editedText, own && styles.messageTimeOwn]}>bearbeitet</Text> : null}
          {item.reactions?.length ? (
            <View style={styles.reactionRow}>
              {item.reactions.map((reaction) => (
                <Text key={reaction.key} style={[styles.reactionPill, reaction.own && styles.reactionPillOwn]}>
                  {reaction.key} {reaction.count || ''}
                </Text>
              ))}
            </View>
          ) : null}
          <View style={styles.messageActions}>
            <Pressable onPress={() => setReplyTarget(item)}>
              <Text style={[styles.actionText, own && styles.actionTextOwn]}>Antworten</Text>
            </Pressable>
            {REACTION_PRESETS.map((reaction) => (
              <Pressable key={reaction} onPress={() => addReaction(item, reaction)}>
                <Text style={[styles.actionText, own && styles.actionTextOwn]}>{reaction}</Text>
              </Pressable>
            ))}
            {own && !item.attachment ? (
              <Pressable onPress={() => openEdit(item)}>
                <Text style={[styles.actionText, styles.actionTextOwn]}>Bearbeiten</Text>
              </Pressable>
            ) : null}
            {own ? (
              <Pressable onPress={() => confirmDelete(item)}>
                <Text style={[styles.actionText, styles.actionTextDestructive]}>Löschen</Text>
              </Pressable>
            ) : null}
          </View>
        </View>
      </View>
    );
  }

  return (
    <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined} style={styles.screen}>
      <View style={styles.header}>
        <View style={styles.headerMain}>
          <Text style={styles.title}>Kommunikation</Text>
          <Text style={styles.subtitle} numberOfLines={1}>
            {activeRoom?.name || 'Matrix Chat'}
          </Text>
        </View>
        <Pressable style={styles.headerButton} onPress={() => setDialogMode('create-room')}>
          <Text style={styles.headerButtonText}>+</Text>
        </Pressable>
        <Pressable style={styles.headerButton} onPress={() => setMembersOpen((value) => !value)}>
          <Text style={styles.headerButtonText}>☰</Text>
        </Pressable>
      </View>

      {error ? <Text style={styles.error}>{error}</Text> : null}

      {status && status.enabled === false ? (
        <View style={styles.notice}>
          <Text style={styles.noticeTitle}>Matrix ist nicht aktiv</Text>
          <Text style={styles.noticeText}>Die Kommunikation ist serverseitig noch nicht aktiviert.</Text>
        </View>
      ) : null}

      {!matrixUserId ? (
        <View style={styles.notice}>
          <Text style={styles.noticeTitle}>Matrix-Benutzer fehlt</Text>
          <Text style={styles.noticeText}>Lege deinen Matrix-Zugang an, um Räume nutzen zu können.</Text>
          <Pressable style={styles.primaryButton} onPress={provisionUser} disabled={provisioning}>
            <Text style={styles.primaryButtonText}>{provisioning ? 'Wird erstellt...' : 'Benutzer erstellen'}</Text>
          </Pressable>
        </View>
      ) : null}

      <View style={styles.roomPanel}>
        <TextInput
          style={styles.searchInput}
          placeholder="Räume, Projekte oder Personen suchen"
          value={search}
          onChangeText={setSearch}
        />
        <FlatList
          data={visibleRooms}
          horizontal
          keyExtractor={(item) => item.key}
          renderItem={renderRoom}
          showsHorizontalScrollIndicator={false}
          contentContainerStyle={styles.roomList}
        />
      </View>

      {membersOpen ? (
        <View style={styles.membersPanel}>
          <View style={styles.membersHeader}>
            <Text style={styles.membersTitle}>Mitglieder · {members.length}</Text>
            <View style={styles.membersActions}>
              <Pressable onPress={syncMembersNow}>
                <Text style={styles.linkText}>Sync</Text>
              </Pressable>
              <Pressable onPress={() => setDialogMode('invite-member')}>
                <Text style={styles.linkText}>Einladen</Text>
              </Pressable>
            </View>
          </View>
          <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.memberList}>
            {members.map((member) => (
              <Pressable key={member.matrixUserId} style={styles.memberPill} onLongPress={() => confirmRemoveMember(member)}>
                <Text style={styles.memberName}>{member.displayName || member.matrixUserId}</Text>
              </Pressable>
            ))}
          </ScrollView>
        </View>
      ) : null}

      {!activeRoom?.exists ? (
        <View style={styles.provisionPanel}>
          <Text style={styles.noticeTitle}>Raum noch nicht bereitgestellt</Text>
          <Text style={styles.noticeText}>Beim Öffnen wird der Matrix-Raum inklusive Einladungen angelegt.</Text>
          <Pressable style={styles.primaryButton} onPress={ensureActiveRoom} disabled={provisioning}>
            <Text style={styles.primaryButtonText}>{provisioning ? 'Wird bereitgestellt...' : 'Raum bereitstellen'}</Text>
          </Pressable>
        </View>
      ) : null}

      {loading ? (
        <View style={styles.loading}>
          <ActivityIndicator />
          <Text style={styles.loadingText}>Nachrichten werden geladen...</Text>
        </View>
      ) : (
        <FlatList
          ref={messageListRef}
          data={messages}
          keyExtractor={(item) => item.id}
          renderItem={renderMessage}
          contentContainerStyle={styles.messageList}
          refreshControl={
            <RefreshControl
              refreshing={refreshing}
              onRefresh={() => {
                setRefreshing(true);
                void refreshAll(false);
              }}
            />
          }
          ListEmptyComponent={<Text style={styles.emptyText}>Noch keine Nachrichten in diesem Raum.</Text>}
          onContentSizeChange={() => messageListRef.current?.scrollToEnd({ animated: true })}
        />
      )}

      {(replyTarget || editingMessage) && !dialogMode ? (
        <View style={styles.composerContext}>
          <View style={styles.composerContextMain}>
            <Text style={styles.composerContextLabel}>{editingMessage ? 'Bearbeiten' : 'Antwort auf'}</Text>
            <Text style={styles.composerContextText} numberOfLines={1}>
              {messagePreview(editingMessage || replyTarget!)}
            </Text>
          </View>
          <Pressable
            onPress={() => {
              setReplyTarget(null);
              setEditingMessage(null);
              setDraft('');
            }}>
            <Text style={styles.linkText}>Abbrechen</Text>
          </Pressable>
        </View>
      ) : null}

      <View style={styles.composer}>
        <Pressable style={styles.attachButton} onPress={pickAttachment} disabled={sending || !activeRoom}>
          <Text style={styles.attachButtonText}>+</Text>
        </Pressable>
        <TextInput
          style={styles.composerInput}
          placeholder="Nachricht schreiben"
          value={draft}
          onChangeText={setDraft}
          multiline
        />
        <Pressable style={[styles.sendButton, (!draft.trim() || sending) && styles.sendButtonDisabled]} onPress={sendMessage}>
          <Text style={styles.sendButtonText}>{sending ? '...' : 'Senden'}</Text>
        </Pressable>
      </View>

      <Modal transparent visible={Boolean(dialogMode)} animationType="fade" onRequestClose={() => setDialogMode(null)}>
        <View style={styles.modalBackdrop}>
          <View style={styles.modalCard}>
            {dialogMode === 'create-room' ? (
              <>
                <Text style={styles.modalTitle}>Raum erstellen</Text>
                <TextInput style={styles.modalInput} placeholder="Name" value={roomName} onChangeText={setRoomName} />
                <TextInput
                  style={styles.modalInput}
                  placeholder="Schlüssel, optional"
                  value={roomKey}
                  onChangeText={setRoomKey}
                  autoCapitalize="none"
                />
                <TextInput style={styles.modalInput} placeholder="Thema, optional" value={roomTopic} onChangeText={setRoomTopic} />
                <View style={styles.modalActions}>
                  <Pressable onPress={() => setDialogMode(null)}>
                    <Text style={styles.linkText}>Abbrechen</Text>
                  </Pressable>
                  <Pressable style={styles.primaryButton} onPress={createRoomFromDialog}>
                    <Text style={styles.primaryButtonText}>Erstellen</Text>
                  </Pressable>
                </View>
              </>
            ) : null}

            {dialogMode === 'edit-message' ? (
              <>
                <Text style={styles.modalTitle}>Nachricht bearbeiten</Text>
                <TextInput style={[styles.modalInput, styles.modalTextarea]} value={dialogText} onChangeText={setDialogText} multiline />
                <View style={styles.modalActions}>
                  <Pressable onPress={() => setDialogMode(null)}>
                    <Text style={styles.linkText}>Abbrechen</Text>
                  </Pressable>
                  <Pressable
                    style={styles.primaryButton}
                    onPress={() => {
                      setDraft(dialogText);
                      setDialogMode(null);
                    }}>
                    <Text style={styles.primaryButtonText}>Übernehmen</Text>
                  </Pressable>
                </View>
              </>
            ) : null}

            {dialogMode === 'invite-member' ? (
              <>
                <Text style={styles.modalTitle}>Mitglied einladen</Text>
                <ScrollView style={styles.inviteList}>
                  {inviteCandidates.map((user) => (
                    <Pressable
                      key={user.userId}
                      style={[styles.inviteRow, selectedUserId === user.userId && styles.inviteRowActive]}
                      onPress={() => setSelectedUserId(user.userId)}>
                      <Text style={styles.inviteName}>{user.displayName || user.email || user.userId}</Text>
                      <Text style={styles.inviteMeta}>{user.matrixUserId}</Text>
                    </Pressable>
                  ))}
                  {!inviteCandidates.length ? <Text style={styles.emptyText}>Keine weiteren Benutzer verfügbar.</Text> : null}
                </ScrollView>
                <View style={styles.modalActions}>
                  <Pressable onPress={() => setDialogMode(null)}>
                    <Text style={styles.linkText}>Abbrechen</Text>
                  </Pressable>
                  <Pressable style={[styles.primaryButton, !selectedUserId && styles.sendButtonDisabled]} onPress={inviteSelectedUser}>
                    <Text style={styles.primaryButtonText}>Einladen</Text>
                  </Pressable>
                </View>
              </>
            ) : null}
          </View>
        </View>
      </Modal>
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  screen: { flex: 1, backgroundColor: '#f9fafb' },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
    paddingHorizontal: 16,
    paddingVertical: 12,
    backgroundColor: '#ffffff',
    borderBottomColor: '#e5e7eb',
    borderBottomWidth: 1,
  },
  headerMain: { flex: 1, minWidth: 0 },
  title: { color: '#111827', fontSize: 20, fontWeight: '800' },
  subtitle: { color: '#6b7280', fontSize: 13, marginTop: 2 },
  headerButton: {
    width: 36,
    height: 36,
    borderRadius: 18,
    alignItems: 'center',
    justifyContent: 'center',
    borderWidth: 1,
    borderColor: '#d1d5db',
    backgroundColor: '#ffffff',
  },
  headerButtonText: { color: '#111827', fontSize: 20, fontWeight: '700' },
  error: { margin: 12, color: '#991b1b', backgroundColor: '#fee2e2', borderRadius: 8, padding: 10 },
  notice: { margin: 12, padding: 12, borderRadius: 10, backgroundColor: '#fff7ed', borderWidth: 1, borderColor: '#fed7aa', gap: 8 },
  noticeTitle: { color: '#111827', fontWeight: '700', fontSize: 15 },
  noticeText: { color: '#6b7280', fontSize: 13 },
  roomPanel: { backgroundColor: '#ffffff', borderBottomWidth: 1, borderBottomColor: '#e5e7eb', paddingVertical: 10 },
  searchInput: {
    marginHorizontal: 16,
    borderWidth: 1,
    borderColor: '#d1d5db',
    borderRadius: 10,
    paddingHorizontal: 12,
    paddingVertical: 9,
    fontSize: 14,
    backgroundColor: '#ffffff',
  },
  roomList: { paddingHorizontal: 12, paddingTop: 10, gap: 8 },
  roomChip: { width: 150, padding: 10, borderRadius: 10, borderWidth: 1, borderColor: '#e5e7eb', backgroundColor: '#ffffff', gap: 3 },
  roomChipActive: { backgroundColor: '#eff9ea', borderColor: PRIMARY },
  roomGroup: { color: '#6b7280', fontSize: 11, textTransform: 'uppercase' },
  roomName: { color: '#111827', fontSize: 14, fontWeight: '700' },
  roomTextActive: { color: '#2f6f25' },
  roomMetaRow: { flexDirection: 'row', gap: 5, minHeight: 18 },
  roomBadge: { color: '#ffffff', backgroundColor: PRIMARY, borderRadius: 9, overflow: 'hidden', paddingHorizontal: 6, fontSize: 11 },
  roomBadgeMuted: { color: '#6b7280', backgroundColor: '#f3f4f6', borderRadius: 9, overflow: 'hidden', paddingHorizontal: 6, fontSize: 11 },
  membersPanel: { backgroundColor: '#ffffff', borderBottomWidth: 1, borderBottomColor: '#e5e7eb', padding: 12, gap: 8 },
  membersHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
  membersTitle: { color: '#111827', fontWeight: '700' },
  membersActions: { flexDirection: 'row', gap: 16 },
  memberList: { gap: 8 },
  memberPill: { backgroundColor: '#f3f4f6', paddingHorizontal: 10, paddingVertical: 7, borderRadius: 16 },
  memberName: { color: '#374151', fontSize: 12 },
  provisionPanel: { margin: 12, padding: 12, borderRadius: 10, backgroundColor: '#ffffff', borderWidth: 1, borderColor: '#e5e7eb', gap: 8 },
  loading: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 8 },
  loadingText: { color: '#6b7280' },
  messageList: { padding: 12, gap: 10, flexGrow: 1 },
  emptyText: { color: '#6b7280', textAlign: 'center', padding: 18 },
  messageRow: { alignItems: 'flex-start' },
  messageRowOwn: { alignItems: 'flex-end' },
  messageBubble: {
    maxWidth: '88%',
    minWidth: 120,
    backgroundColor: '#ffffff',
    borderRadius: 12,
    borderWidth: 1,
    borderColor: '#e5e7eb',
    padding: 10,
    gap: 6,
  },
  messageBubbleOwn: { backgroundColor: '#3f8f32', borderColor: '#3f8f32' },
  messageHeader: { flexDirection: 'row', justifyContent: 'space-between', gap: 10 },
  messageSender: { flex: 1, color: '#111827', fontSize: 12, fontWeight: '700' },
  messageSenderOwn: { color: '#ffffff' },
  messageTime: { color: '#6b7280', fontSize: 11 },
  messageTimeOwn: { color: '#dff4d9' },
  messageBody: { color: '#111827', fontSize: 15, lineHeight: 21 },
  messageBodyOwn: { color: '#ffffff' },
  replyBox: { backgroundColor: '#f3f4f6', borderRadius: 8, borderLeftWidth: 3, borderLeftColor: PRIMARY, padding: 7 },
  replyBoxOwn: { backgroundColor: '#327628', borderLeftColor: '#dff4d9' },
  replyText: { color: '#4b5563', fontSize: 12 },
  replyTextOwn: { color: '#dff4d9' },
  attachmentBox: { borderWidth: 1, borderColor: '#d1d5db', borderRadius: 8, padding: 8, gap: 2 },
  attachmentBoxOwn: { borderColor: '#dff4d9' },
  attachmentTitle: { color: '#111827', fontWeight: '700' },
  attachmentMeta: { color: '#6b7280', fontSize: 12 },
  editedText: { color: '#6b7280', fontSize: 11 },
  reactionRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 5 },
  reactionPill: { backgroundColor: '#f3f4f6', borderRadius: 12, overflow: 'hidden', paddingHorizontal: 7, paddingVertical: 2, fontSize: 12 },
  reactionPillOwn: { backgroundColor: '#dff4d9' },
  messageActions: { flexDirection: 'row', flexWrap: 'wrap', gap: 12, paddingTop: 2 },
  actionText: { color: '#3f8f32', fontSize: 12, fontWeight: '700' },
  actionTextOwn: { color: '#ffffff' },
  actionTextDestructive: { color: '#fee2e2' },
  composerContext: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 12,
    paddingHorizontal: 12,
    paddingVertical: 8,
    backgroundColor: '#ffffff',
    borderTopWidth: 1,
    borderTopColor: '#e5e7eb',
  },
  composerContextMain: { flex: 1, minWidth: 0 },
  composerContextLabel: { color: '#6b7280', fontSize: 11, textTransform: 'uppercase' },
  composerContextText: { color: '#111827', fontSize: 13, fontWeight: '600' },
  composer: { flexDirection: 'row', alignItems: 'flex-end', gap: 8, padding: 10, backgroundColor: '#ffffff', borderTopWidth: 1, borderTopColor: '#e5e7eb' },
  attachButton: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center', backgroundColor: '#f3f4f6' },
  attachButtonText: { color: '#111827', fontSize: 22, fontWeight: '700' },
  composerInput: { flex: 1, maxHeight: 110, borderRadius: 18, backgroundColor: '#f3f4f6', paddingHorizontal: 12, paddingVertical: 10, fontSize: 15 },
  sendButton: { minWidth: 70, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center', backgroundColor: PRIMARY, paddingHorizontal: 12 },
  sendButtonDisabled: { opacity: 0.45 },
  sendButtonText: { color: '#ffffff', fontWeight: '800' },
  primaryButton: { alignSelf: 'flex-start', backgroundColor: PRIMARY, borderRadius: 9, paddingHorizontal: 12, paddingVertical: 9 },
  primaryButtonText: { color: '#ffffff', fontWeight: '800' },
  linkText: { color: '#3f8f32', fontWeight: '800' },
  modalBackdrop: { flex: 1, backgroundColor: 'rgba(17, 24, 39, 0.45)', alignItems: 'center', justifyContent: 'center', padding: 18 },
  modalCard: { width: '100%', maxWidth: 420, borderRadius: 12, backgroundColor: '#ffffff', padding: 16, gap: 12 },
  modalTitle: { color: '#111827', fontSize: 18, fontWeight: '800' },
  modalInput: { borderWidth: 1, borderColor: '#d1d5db', borderRadius: 9, paddingHorizontal: 12, paddingVertical: 10, fontSize: 15 },
  modalTextarea: { minHeight: 110, textAlignVertical: 'top' },
  modalActions: { flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'center', gap: 14 },
  inviteList: { maxHeight: 280 },
  inviteRow: { padding: 10, borderRadius: 9, borderWidth: 1, borderColor: '#e5e7eb', marginBottom: 8 },
  inviteRowActive: { borderColor: PRIMARY, backgroundColor: '#eff9ea' },
  inviteName: { color: '#111827', fontWeight: '700' },
  inviteMeta: { color: '#6b7280', fontSize: 12, marginTop: 2 },
});
