<script lang="ts">
	import { onMount, getContext } from "svelte";
	import { browser } from "$app/environment";
	import { page } from "$app/state";
	import { Avatar, Button, Input, Modal } from "$lib/components/ui";
	import {
		MessageList,
		MessageInput,
		TypingIndicator,
		CreateRoomModal,
		MemberList,
		StartDMModal,
		RoomInfoPanel,
		MatrixProvider,
	} from "$lib/components/matrix";
	import type { MatrixClient } from "matrix-js-sdk";
	import {
		initMatrixClient,
		setupSyncHandlers,
		logout as matrixLogout,
		editMessage,
		deleteMessage,
		loadMoreMessages,
		getRoomMembers,
		searchMessagesLocal,
		uploadFile,
		sendFileMessage,
		type LoginCredentials,
	} from "$lib/matrix";
	import {
		auth,
		syncState,
		roomSummaries,
		selectedRoomId,
		selectRoom,
		clearState,
		currentMessages,
		currentTyping,
		loadRoomMessages,
	} from "$lib/stores/matrix";
	import { reactionService } from "$lib/services";
	import { toasts } from "$lib/stores/toast.svelte";
	import { initCache, cleanupCache } from "$lib/cache";
	import { clearBlobUrlCache } from "$lib/cache/mediaCache";
	import type { Message } from "$lib/matrix/types";
	import type { SupabaseClient } from "@supabase/supabase-js";

	const supabase = getContext<SupabaseClient>("supabase");
	let data = $derived(page.data);

	// Matrix state
	let matrixClient = $state<MatrixClient | null>(null);
	let isInitializing = $state(true);
	let showMatrixLogin = $state(false);

	// Matrix login form
	let matrixHomeserver = $state("https://matrix.org");
	let matrixUsername = $state("");
	let matrixPassword = $state("");
	let isLoggingIn = $state(false);

	// Chat UI state
	let showCreateRoomModal = $state(false);
	let showStartDMModal = $state(false);
	let replyToMessage = $state<Message | null>(null);
	let editingMsg = $state<Message | null>(null);
	let isLoadingMore = $state(false);
	let showMemberList = $state(false);
	let showRoomInfo = $state(false);
	let roomSearchQuery = $state("");
	let showMessageSearch = $state(false);
	let messageSearchQuery = $state("");
	let isDraggingFile = $state(false);
	let isUploadingDrop = $state(false);

	const messageSearchResults = $derived(
		messageSearchQuery.trim() && $selectedRoomId
			? searchMessagesLocal($selectedRoomId, messageSearchQuery)
			: [],
	);

	// All non-space rooms (exclude Space entries themselves from the list)
	const allRooms = $derived(
		$roomSummaries.filter((r) => !r.isSpace),
	);

	// Org rooms: rooms that belong to any Space
	const orgRooms = $derived(
		allRooms.filter((r) => r.parentSpaceId && !r.isDirect),
	);

	// DMs: direct messages (not tied to org)
	const dmRooms = $derived(
		allRooms.filter((r) => r.isDirect),
	);

	// Other rooms: not in a space and not a DM
	const otherRooms = $derived(
		allRooms.filter((r) => !r.parentSpaceId && !r.isDirect),
	);

	// Apply search filter across all sections
	const filterBySearch = (rooms: typeof allRooms) =>
		roomSearchQuery.trim()
			? rooms.filter(
					(room) =>
						room.name.toLowerCase().includes(roomSearchQuery.toLowerCase()) ||
						room.topic?.toLowerCase().includes(roomSearchQuery.toLowerCase()),
				)
			: rooms;

	const filteredOrgRooms = $derived(filterBySearch(orgRooms));
	const filteredDmRooms = $derived(filterBySearch(dmRooms));
	const filteredOtherRooms = $derived(filterBySearch(otherRooms));

	const currentMembers = $derived(
		$selectedRoomId ? getRoomMembers($selectedRoomId) : [],
	);

	onMount(async () => {
		if (!browser) return;

		try {
			await initCache();
			await cleanupCache(7 * 24 * 60 * 60 * 1000);
		} catch (e) {
			console.warn("Cache initialization failed:", e);
		}

		// Try to load credentials from Supabase
		try {
			const res = await fetch(`/api/matrix-credentials?org_id=${data.org.id}`);
			const result = await res.json();

			if (result.credentials) {
				await initFromCredentials({
					homeserverUrl: result.credentials.homeserver_url,
					userId: result.credentials.matrix_user_id,
					accessToken: result.credentials.access_token,
					deviceId: result.credentials.device_id,
				});
			} else {
				// No stored credentials — show login form
				showMatrixLogin = true;
				isInitializing = false;
			}
		} catch (e) {
			console.error("Failed to load Matrix credentials:", e);
			showMatrixLogin = true;
			isInitializing = false;
		}
	});

	async function initFromCredentials(credentials: LoginCredentials) {
		try {
			const client = await initMatrixClient(credentials);
			matrixClient = client;
			setupSyncHandlers(client);

			auth.set({
				isLoggedIn: true,
				userId: credentials.userId,
				homeserverUrl: credentials.homeserverUrl,
				accessToken: credentials.accessToken,
				deviceId: credentials.deviceId || null,
			});

			// Check if org has a Matrix Space, auto-create if not
			await ensureOrgSpace(credentials);
		} catch (e: unknown) {
			console.error("Failed to init Matrix client:", e);
			toasts.error("Failed to connect to chat. Please re-login.");
			showMatrixLogin = true;
		} finally {
			isInitializing = false;
		}
	}

	async function ensureOrgSpace(credentials: LoginCredentials) {
		try {
			const spaceRes = await fetch(`/api/matrix-space?org_id=${data.org.id}`);
			const spaceResult = await spaceRes.json();

			if (!spaceResult.spaceId) {
				// No Space yet — create one using the user's credentials
				const createRes = await fetch("/api/matrix-space", {
					method: "POST",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify({
						org_id: data.org.id,
						action: "create",
						homeserver_url: credentials.homeserverUrl,
						access_token: credentials.accessToken,
						org_name: data.org.name,
					}),
				});
				const createResult = await createRes.json();
				if (createResult.spaceId) {
					toasts.success(`Organization space created`);
				}
			}
		} catch (e) {
			console.warn("Failed to ensure org space:", e);
		}
	}

	async function handleMatrixLogin() {
		if (!matrixUsername.trim() || !matrixPassword.trim()) {
			toasts.error("Please enter username and password");
			return;
		}

		isLoggingIn = true;
		try {
			const { loginWithPassword } = await import("$lib/matrix");
			const credentials = await loginWithPassword({
				homeserverUrl: matrixHomeserver,
				username: matrixUsername.trim(),
				password: matrixPassword,
			});

			// Save to Supabase
			await fetch("/api/matrix-credentials", {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({
					org_id: data.org.id,
					homeserver_url: credentials.homeserverUrl,
					matrix_user_id: credentials.userId,
					access_token: credentials.accessToken,
					device_id: credentials.deviceId,
				}),
			});

			showMatrixLogin = false;
			await initFromCredentials(credentials);
			toasts.success("Connected to chat!");
		} catch (e: any) {
			toasts.error(e.message || "Login failed");
		} finally {
			isLoggingIn = false;
		}
	}

	async function handleLogout() {
		try {
			await matrixLogout();
		} catch {}
		clearState();
		clearBlobUrlCache();

		// Remove from Supabase
		await fetch(`/api/matrix-credentials?org_id=${data.org.id}`, {
			method: "DELETE",
		});

		matrixClient = null;
		showMatrixLogin = true;
		auth.set({
			isLoggedIn: false,
			userId: null,
			homeserverUrl: null,
			accessToken: null,
			deviceId: null,
		});
	}

	function handleRoomSelect(roomId: string) {
		selectRoom(roomId);
	}

	async function handleReact(messageId: string, emoji: string) {
		if (!$selectedRoomId || !$auth.userId) return;
		try {
			await reactionService.add($selectedRoomId, messageId, emoji, $auth.userId);
		} catch (e) {
			const error = e as { message?: string };
			toasts.error(error.message || "Failed to add reaction");
		}
	}

	async function handleToggleReaction(
		messageId: string,
		emoji: string,
		reactionEventId: string | null,
	) {
		if (!$selectedRoomId || !$auth.userId) return;
		try {
			await reactionService.toggle(
				$selectedRoomId,
				messageId,
				emoji,
				$auth.userId,
				reactionEventId,
			);
		} catch (e) {
			const error = e as { message?: string };
			toasts.error(error.message || "Failed to toggle reaction");
		}
	}

	function handleEditMessage(message: Message) {
		editingMsg = message;
	}

	async function handleSaveEdit(newContent: string) {
		if (!$selectedRoomId || !editingMsg) return;
		try {
			await editMessage($selectedRoomId, editingMsg.eventId, newContent);
			editingMsg = null;
			toasts.success("Message edited");
		} catch (e: any) {
			toasts.error(e.message || "Failed to edit message");
		}
	}

	function cancelEdit() {
		editingMsg = null;
	}

	async function handleDeleteMessage(messageId: string) {
		if (!$selectedRoomId) return;
		if (!confirm("Delete this message?")) return;
		try {
			await deleteMessage($selectedRoomId, messageId);
			toasts.success("Message deleted");
		} catch (e: any) {
			toasts.error(e.message || "Failed to delete message");
		}
	}

	function handleReply(message: Message) {
		replyToMessage = message;
	}

	function cancelReply() {
		replyToMessage = null;
	}

	function handleDragOver(e: DragEvent) {
		e.preventDefault();
		if (e.dataTransfer?.types.includes("Files")) isDraggingFile = true;
	}

	function handleDragLeave(e: DragEvent) {
		e.preventDefault();
		isDraggingFile = false;
	}

	async function handleDrop(e: DragEvent) {
		e.preventDefault();
		isDraggingFile = false;
		if (!$selectedRoomId || isUploadingDrop) return;

		const files = e.dataTransfer?.files;
		if (!files || files.length === 0) return;

		const file = files[0];
		if (file.size > 50 * 1024 * 1024) {
			toasts.error("File too large. Maximum size is 50MB.");
			return;
		}

		isUploadingDrop = true;
		try {
			toasts.info(`Uploading ${file.name}...`);
			const contentUri = await uploadFile(file);
			await sendFileMessage($selectedRoomId, file, contentUri);
			toasts.success("File sent!");
		} catch (e: any) {
			toasts.error(e.message || "Failed to upload file");
		} finally {
			isUploadingDrop = false;
		}
	}

	async function handleLoadMore() {
		if (!$selectedRoomId || isLoadingMore) return;
		isLoadingMore = true;
		try {
			const result = await loadMoreMessages($selectedRoomId);
			loadRoomMessages($selectedRoomId);
			if (!result.hasMore) toasts.info("No more messages to load");
		} catch (e: any) {
			console.error("Failed to load more messages:", e);
		} finally {
			isLoadingMore = false;
		}
	}
</script>

<!-- Matrix Login Modal -->
{#if showMatrixLogin}
	<div class="h-full flex items-center justify-center">
		<div class="bg-dark/30 border border-light/5 rounded-xl p-8 w-full max-w-md">
			<h2 class="font-heading text-body text-white mb-1">Connect to Chat</h2>
			<p class="text-body-sm text-light/50 mb-6">
				Enter your Matrix credentials to enable messaging.
			</p>

			<div class="space-y-4">
				<Input
					label="Homeserver URL"
					bind:value={matrixHomeserver}
					placeholder="https://matrix.org"
				/>
				<Input
					label="Username"
					bind:value={matrixUsername}
					placeholder="@user:matrix.org"
				/>
				<div>
					<label class="block text-body-sm font-body text-light/60 mb-1">Password</label>
					<input
						type="password"
						bind:value={matrixPassword}
						placeholder="Password"
						class="w-full bg-dark border border-light/10 rounded-xl px-3 py-2 text-white font-body text-body-sm placeholder:text-light/30 focus:outline-none focus:border-primary"
						onkeydown={(e) => {
							if (e.key === "Enter") handleMatrixLogin();
						}}
					/>
				</div>
				<Button
					variant="primary"
					fullWidth
					onclick={handleMatrixLogin}
					disabled={isLoggingIn}
				>
					{isLoggingIn ? "Connecting..." : "Connect"}
				</Button>
			</div>
		</div>
	</div>

<!-- Loading state -->
{:else if isInitializing || ($syncState !== "PREPARED" && $syncState !== "SYNCING")}
	<div class="h-full flex items-center justify-center">
		<div class="text-center">
			<div
				class="animate-spin w-10 h-10 border-3 border-primary border-t-transparent rounded-full mx-auto mb-4"
			></div>
			<p class="text-body-sm text-light/40">
				{#if isInitializing}
					Connecting to Matrix...
				{:else if $syncState === "CATCHUP"}
					Catching up on messages...
				{:else if $syncState === "RECONNECTING"}
					Reconnecting...
				{:else if $syncState === "ERROR"}
					Connection error, retrying...
				{:else}
					Syncing...
				{/if}
			</p>
		</div>
	</div>

<!-- Main Chat UI -->
{:else if matrixClient}
	<MatrixProvider client={matrixClient}>
		{#snippet children()}
			<div class="h-full flex min-h-0">
				<!-- Chat Sidebar -->
				<aside class="w-56 border-r border-light/5 flex flex-col overflow-hidden shrink-0">
					<div class="flex items-center gap-2 px-3 py-2.5 border-b border-light/5">
						<span class="flex-1 font-heading text-body-sm text-white">Messages</span>
						<button
							class="p-1 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
							onclick={() => (showStartDMModal = true)}
							title="New message"
						>
							<span class="material-symbols-rounded" style="font-size: 18px;">add</span>
						</button>
					</div>

					<!-- Room search -->
					<div class="px-2 py-2">
						<div class="relative">
							<span
								class="material-symbols-rounded absolute left-2.5 top-1/2 -translate-y-1/2 text-light/30"
								style="font-size: 16px;"
							>search</span>
							<input
								type="text"
								bind:value={roomSearchQuery}
								placeholder="Search..."
								class="w-full pl-8 pr-3 py-1.5 bg-dark/50 text-white text-[12px] rounded-lg border border-light/5 placeholder:text-light/30 focus:outline-none focus:border-primary"
							/>
						</div>
					</div>

					<!-- Room list (sectioned) -->
					<nav class="flex-1 overflow-y-auto px-1.5 pb-2">
						{#if allRooms.length === 0}
							<p class="text-light/30 text-[12px] text-center py-8">
								{roomSearchQuery ? "No matching rooms" : "No rooms yet"}
							</p>
						{:else}
							<!-- Org / Space Rooms -->
							{#if filteredOrgRooms.length > 0}
								<div class="mb-1.5">
									<div class="flex items-center justify-between px-2 py-1">
										<span class="text-[10px] font-body text-light/30 uppercase tracking-wider">Organization</span>
										<button
											class="p-0.5 text-light/30 hover:text-white hover:bg-dark/50 rounded transition-colors"
											onclick={() => (showCreateRoomModal = true)}
											title="Create room"
										>
											<span class="material-symbols-rounded" style="font-size: 14px;">add</span>
										</button>
									</div>
									<ul class="flex flex-col gap-0.5">
										{#each filteredOrgRooms as room (room.roomId)}
											<li>
												<button
													class="w-full flex items-center gap-2 px-2 py-1.5 rounded-lg transition-colors text-left
														{$selectedRoomId === room.roomId ? 'bg-primary/10 text-white' : 'text-light/60 hover:bg-dark/50 hover:text-white'}"
													onclick={() => handleRoomSelect(room.roomId)}
												>
													<Avatar src={room.avatarUrl} name={room.name} size="xs" />
													<div class="flex-1 min-w-0">
														<span class="text-[12px] font-body truncate block">{room.name}</span>
													</div>
													{#if room.unreadCount > 0}
														<span class="bg-primary text-background text-[10px] px-1.5 py-0.5 rounded-full min-w-[16px] text-center font-bold">
															{room.unreadCount > 99 ? "99+" : room.unreadCount}
														</span>
													{/if}
												</button>
											</li>
										{/each}
									</ul>
								</div>
							{/if}

							<!-- Direct Messages -->
							{#if filteredDmRooms.length > 0}
								<div class="mb-1.5">
									<div class="flex items-center justify-between px-2 py-1">
										<span class="text-[10px] font-body text-light/30 uppercase tracking-wider">Direct Messages</span>
										<button
											class="p-0.5 text-light/30 hover:text-white hover:bg-dark/50 rounded transition-colors"
											onclick={() => (showStartDMModal = true)}
											title="New DM"
										>
											<span class="material-symbols-rounded" style="font-size: 14px;">add</span>
										</button>
									</div>
									<ul class="flex flex-col gap-0.5">
										{#each filteredDmRooms as room (room.roomId)}
											<li>
												<button
													class="w-full flex items-center gap-2 px-2 py-1.5 rounded-lg transition-colors text-left
														{$selectedRoomId === room.roomId ? 'bg-primary/10 text-white' : 'text-light/60 hover:bg-dark/50 hover:text-white'}"
													onclick={() => handleRoomSelect(room.roomId)}
												>
													<Avatar src={room.avatarUrl} name={room.name} size="xs" />
													<div class="flex-1 min-w-0">
														<span class="text-[12px] font-body truncate block">{room.name}</span>
													</div>
													{#if room.unreadCount > 0}
														<span class="bg-primary text-background text-[10px] px-1.5 py-0.5 rounded-full min-w-[16px] text-center font-bold">
															{room.unreadCount > 99 ? "99+" : room.unreadCount}
														</span>
													{/if}
												</button>
											</li>
										{/each}
									</ul>
								</div>
							{/if}

							<!-- Other Rooms (not in a space, not DMs) -->
							{#if filteredOtherRooms.length > 0}
								<div class="mb-1.5">
									<div class="flex items-center justify-between px-2 py-1">
										<span class="text-[10px] font-body text-light/30 uppercase tracking-wider">Rooms</span>
										<button
											class="p-0.5 text-light/30 hover:text-white hover:bg-dark/50 rounded transition-colors"
											onclick={() => (showCreateRoomModal = true)}
											title="Create room"
										>
											<span class="material-symbols-rounded" style="font-size: 14px;">add</span>
										</button>
									</div>
									<ul class="flex flex-col gap-0.5">
										{#each filteredOtherRooms as room (room.roomId)}
											<li>
												<button
													class="w-full flex items-center gap-2 px-2 py-1.5 rounded-lg transition-colors text-left
														{$selectedRoomId === room.roomId ? 'bg-primary/10 text-white' : 'text-light/60 hover:bg-dark/50 hover:text-white'}"
													onclick={() => handleRoomSelect(room.roomId)}
												>
													<Avatar src={room.avatarUrl} name={room.name} size="xs" />
													<div class="flex-1 min-w-0">
														<span class="text-[12px] font-body truncate block">{room.name}</span>
													</div>
													{#if room.unreadCount > 0}
														<span class="bg-primary text-background text-[10px] px-1.5 py-0.5 rounded-full min-w-[16px] text-center font-bold">
															{room.unreadCount > 99 ? "99+" : room.unreadCount}
														</span>
													{/if}
												</button>
											</li>
										{/each}
									</ul>
								</div>
							{/if}
						{/if}
					</nav>

					<!-- User footer -->
					<div class="px-2 py-2 border-t border-light/5">
						<div class="flex items-center gap-2">
							<Avatar name={$auth.userId || "User"} size="xs" status="online" />
							<div class="flex-1 min-w-0">
								<p class="text-[11px] text-light/50 truncate">{$auth.userId}</p>
							</div>
							<button
								class="p-1 text-light/30 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
								onclick={handleLogout}
								title="Disconnect chat"
							>
								<span class="material-symbols-rounded" style="font-size: 16px;">logout</span>
							</button>
						</div>
					</div>
				</aside>

				<!-- Main Chat Area -->
				<main class="flex-1 flex flex-col min-h-0 overflow-hidden">
					{#if $selectedRoomId}
						<div class="flex-1 flex flex-col min-h-0 overflow-hidden">
							<!-- Room Header -->
							<div class="px-4 py-2.5 flex items-center border-b border-light/5 shrink-0">
								{#each $roomSummaries.filter((r) => r.roomId === $selectedRoomId) as room}
									<div class="flex items-center gap-2.5 w-full">
										<Avatar src={room.avatarUrl} name={room.name} size="sm" />
										<div class="flex-1 min-w-0">
											<h2 class="font-heading text-body-sm text-white truncate">{room.name}</h2>
											<p class="text-[11px] text-light/40">
												{room.memberCount} members{room.isEncrypted ? " · Encrypted" : ""}
											</p>
										</div>
										<button
											class="p-1.5 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
											onclick={() => (showMessageSearch = !showMessageSearch)}
											title="Search messages"
										>
											<span class="material-symbols-rounded" style="font-size: 18px;">search</span>
										</button>
										<button
											class="p-1.5 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
											onclick={() => (showRoomInfo = !showRoomInfo)}
											title="Room info"
										>
											<span class="material-symbols-rounded" style="font-size: 18px;">info</span>
										</button>
										<button
											class="p-1.5 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
											onclick={() => (showMemberList = !showMemberList)}
											title="Members"
										>
											<span class="material-symbols-rounded" style="font-size: 18px;">group</span>
										</button>
									</div>
								{/each}
							</div>

							<!-- Message search panel -->
							{#if showMessageSearch}
								<div class="border-b border-light/5 px-4 py-2.5">
									<div class="relative">
										<span class="material-symbols-rounded absolute left-2.5 top-1/2 -translate-y-1/2 text-light/30" style="font-size: 16px;">search</span>
										<input
											type="text"
											bind:value={messageSearchQuery}
											placeholder="Search messages..."
											class="w-full pl-8 pr-8 py-1.5 bg-dark/50 text-white text-[12px] rounded-lg border border-light/5 placeholder:text-light/30 focus:outline-none focus:border-primary"
										/>
										<button
											class="absolute right-2 top-1/2 -translate-y-1/2 text-light/30 hover:text-white"
											onclick={() => { showMessageSearch = false; messageSearchQuery = ""; }}
										>
											<span class="material-symbols-rounded" style="font-size: 16px;">close</span>
										</button>
									</div>
									{#if messageSearchQuery && messageSearchResults.length > 0}
										<div class="mt-2 max-h-48 overflow-y-auto">
											<p class="text-[11px] text-light/30 mb-1.5">
												{messageSearchResults.length} result{messageSearchResults.length !== 1 ? "s" : ""}
											</p>
											{#each messageSearchResults.slice(0, 20) as result}
												<button
													class="w-full text-left px-3 py-1.5 hover:bg-dark/50 rounded-lg transition-colors"
													onclick={() => { showMessageSearch = false; messageSearchQuery = ""; }}
												>
													<p class="text-[11px] text-primary">{result.senderName}</p>
													<p class="text-body-sm text-white truncate">{result.content}</p>
													<p class="text-[10px] text-light/30">{new Date(result.timestamp).toLocaleString()}</p>
												</button>
											{/each}
										</div>
									{:else if messageSearchQuery}
										<p class="text-body-sm text-light/30 mt-2">No results found</p>
									{/if}
								</div>
							{/if}

							<!-- Messages area with drag-drop -->
							<div
								class="flex-1 flex min-h-0 overflow-hidden relative"
								ondragover={handleDragOver}
								ondragleave={handleDragLeave}
								ondrop={handleDrop}
								role="region"
							>
								{#if isDraggingFile}
									<div class="absolute inset-0 z-50 bg-primary/10 border-2 border-dashed border-primary rounded-xl flex items-center justify-center backdrop-blur-sm">
										<div class="text-center">
											<span class="material-symbols-rounded text-primary mb-3 block" style="font-size: 48px; font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 48;">upload_file</span>
											<p class="text-body-sm font-heading text-primary">Drop to upload</p>
											<p class="text-[12px] text-light/40 mt-0.5">Release to send file</p>
										</div>
									</div>
								{/if}

								<!-- Messages column -->
								<div class="flex-1 flex flex-col min-h-0 overflow-hidden">
									<MessageList
										messages={$currentMessages}
										onReact={handleReact}
										onToggleReaction={handleToggleReaction}
										onEdit={handleEditMessage}
										onDelete={handleDeleteMessage}
										onReply={handleReply}
										onLoadMore={handleLoadMore}
										isLoading={isLoadingMore}
									/>
									<TypingIndicator userNames={$currentTyping} />
									<MessageInput
										roomId={$selectedRoomId}
										replyTo={replyToMessage}
										onCancelReply={cancelReply}
										editingMessage={editingMsg}
										onSaveEdit={handleSaveEdit}
										onCancelEdit={cancelEdit}
									/>
								</div>

								<!-- Side panels -->
								{#if showRoomInfo}
									{#each $roomSummaries.filter((r) => r.roomId === $selectedRoomId) as currentRoom}
										<aside class="w-72 border-l border-light/5">
											<RoomInfoPanel
												room={currentRoom}
												members={currentMembers}
												onClose={() => (showRoomInfo = false)}
											/>
										</aside>
									{/each}
								{:else if showMemberList}
									<aside class="w-64 border-l border-light/5">
										<MemberList members={currentMembers} />
									</aside>
								{/if}
							</div>
						</div>
					{:else}
						<!-- No room selected -->
						<div class="flex-1 flex items-center justify-center">
							<div class="text-center text-light/30">
								<span class="material-symbols-rounded mb-3 block" style="font-size: 48px; font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 48;">chat</span>
								<p class="text-body-sm text-light/40 mb-1">Select a room</p>
								<p class="text-[12px] text-light/20">Choose a conversation to start chatting</p>
							</div>
						</div>
					{/if}
				</main>
			</div>
		{/snippet}
	</MatrixProvider>
{/if}

<!-- Modals -->
<CreateRoomModal isOpen={showCreateRoomModal} onClose={() => (showCreateRoomModal = false)} />

{#if showStartDMModal}
	<StartDMModal
		onClose={() => (showStartDMModal = false)}
		onDMCreated={(roomId) => handleRoomSelect(roomId)}
	/>
{/if}
