<script lang="ts">
	import type { Node } from '$lib/realtime';
	import { edgeStore, nodeStore } from '$lib/realtime';
	import TraitPanel from './TraitPanel.svelte';
	import {
		joinCommunication,
		leaveCommunication,
		type JoinCommunicationResponse,
	} from '$lib/api';
	import {
		connect,
		disconnect,
		toggleMute,
		getStatus,
		getParticipants,
		getLocalIdentity,
		subscribe,
		type LiveKitParticipant,
		type RoomStatus,
	} from '$lib/livekit';

	interface Props {
		collection?: Node;
		config: Record<string, unknown>;
		accessToken?: string;
	}

	let { collection, config, accessToken }: Props = $props();

	let status = $state<RoomStatus>('disconnected');
	let participants: LiveKitParticipant[] = $state([]);
	let localIdentity: string = $state('');
	let error: string | null = $state(null);
	let joinInfo: JoinCommunicationResponse | null = $state(null);

	// Subscribe to LiveKit state changes
	$effect(() => {
		const unsub = subscribe(() => {
			status = getStatus();
			participants = getParticipants();
			localIdentity = getLocalIdentity();
		});
		return unsub;
	});

	// Clean up on component destroy
	$effect(() => {
		return () => {
			if (status !== 'disconnected') {
				disconnect();
			}
		};
	});

	/** Find communication nodes linked to this collection */
	const communicationNodes = $derived.by(() => {
		const nodes: Node[] = [];
		if (!collection) return nodes;
		for (const edge of edgeStore.byTarget(collection.id)) {
			if (edge.edgeType !== 'belongs_to') continue;
			const node = nodeStore.get(edge.sourceId);
			if (node && node.nodeKind === 'communication') {
				nodes.push(node);
			}
		}
		for (const edge of edgeStore.bySource(collection.id)) {
			if (edge.edgeType !== 'has_channel') continue;
			const node = nodeStore.get(edge.targetId);
			if (node && node.nodeKind === 'communication') {
				nodes.push(node);
			}
		}
		return nodes;
	});

	const primaryComm = $derived(communicationNodes[0] ?? null);

	async function handleJoin() {
		if (!accessToken || !primaryComm) return;
		error = null;

		try {
			const resp = await joinCommunication(accessToken, {
				communication_id: primaryComm.id,
			});
			joinInfo = resp;
			await connect(resp.livekit_url, resp.livekit_token);
		} catch (e) {
			error = e instanceof Error ? e.message : String(e);
		}
	}

	async function handleLeave() {
		if (!accessToken || !primaryComm) return;
		error = null;

		try {
			await disconnect();
			await leaveCommunication(accessToken, primaryComm.id);
			joinInfo = null;
		} catch (e) {
			error = e instanceof Error ? e.message : String(e);
		}
	}

	async function handleToggleMute() {
		try {
			await toggleMute();
		} catch (e) {
			error = e instanceof Error ? e.message : String(e);
		}
	}

	const isConnected = $derived(status === 'connected');
	const isConnecting = $derived(status === 'connecting' || status === 'reconnecting');
	const localParticipant = $derived(participants.find(p => p.identity === localIdentity));
	const remoteParticipants = $derived(participants.filter(p => p.identity !== localIdentity));
</script>

<TraitPanel name="recording" label="Opptak" icon="🎤">
	{#snippet children()}
		{#if !accessToken}
			<p class="text-sm text-gray-400">Logg inn for å bruke opptak.</p>
		{:else if !primaryComm}
			<p class="text-sm text-gray-400">Ingen kommunikasjonskanal knyttet til denne samlingen.</p>
		{:else}
			<!-- Status & controls -->
			<div class="flex items-center justify-between">
				<div class="flex items-center gap-2">
					<span class="inline-block h-2.5 w-2.5 rounded-full {isConnected ? 'bg-green-500' : isConnecting ? 'bg-yellow-400 animate-pulse' : 'bg-gray-300'}"></span>
					<span class="text-sm text-gray-600">
						{#if isConnected}
							Tilkoblet
						{:else if isConnecting}
							Kobler til…
						{:else}
							Frakoblet
						{/if}
					</span>
				</div>

				<div class="flex gap-2">
					{#if isConnected}
						<button
							onclick={handleToggleMute}
							class="rounded-lg px-3 py-1.5 text-xs font-medium transition-colors {localParticipant?.isMuted ? 'bg-red-100 text-red-700 hover:bg-red-200' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}"
						>
							{localParticipant?.isMuted ? 'Slå på mikrofon' : 'Demp'}
						</button>
						<button
							onclick={handleLeave}
							class="rounded-lg bg-red-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-red-700 transition-colors"
						>
							Forlat
						</button>
					{:else}
						<button
							onclick={handleJoin}
							disabled={isConnecting}
							class="rounded-lg bg-indigo-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-indigo-700 disabled:opacity-50 transition-colors"
						>
							{isConnecting ? 'Kobler til…' : 'Koble til'}
						</button>
					{/if}
				</div>
			</div>

			<!-- Error -->
			{#if error}
				<div class="mt-3 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700">
					{error}
				</div>
			{/if}

			<!-- Participant list -->
			{#if isConnected && participants.length > 0}
				<div class="mt-4">
					<h4 class="mb-2 text-xs font-medium text-gray-500 uppercase tracking-wide">
						Deltakere ({participants.length})
					</h4>
					<ul class="space-y-1.5">
						{#each participants as p (p.identity)}
							<li class="flex items-center gap-2 rounded-lg px-2.5 py-1.5 {p.isSpeaking ? 'bg-green-50' : 'bg-gray-50'}">
								<!-- Speaking indicator -->
								<span class="inline-block h-2 w-2 rounded-full flex-shrink-0 {p.isSpeaking ? 'bg-green-500' : p.isMuted ? 'bg-red-400' : 'bg-gray-300'}"></span>

								<!-- Name -->
								<span class="text-sm text-gray-700 truncate flex-1">
									{p.displayName}
									{#if p.identity === localIdentity}
										<span class="text-xs text-gray-400">(deg)</span>
									{/if}
								</span>

								<!-- Mute icon -->
								{#if p.isMuted}
									<span class="text-xs text-red-400 flex-shrink-0" title="Dempet">
										<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" viewBox="0 0 20 20" fill="currentColor">
											<path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM12.293 7.293a1 1 0 011.414 0L15 8.586l1.293-1.293a1 1 0 111.414 1.414L16.414 10l1.293 1.293a1 1 0 01-1.414 1.414L15 11.414l-1.293 1.293a1 1 0 01-1.414-1.414L13.586 10l-1.293-1.293a1 1 0 010-1.414z" clip-rule="evenodd" />
										</svg>
									</span>
								{/if}
							</li>
						{/each}
					</ul>
				</div>
			{/if}

			<!-- Room info (debug) -->
			{#if isConnected && joinInfo}
				<p class="mt-3 text-xs text-gray-400">
					Rom: {joinInfo.livekit_room_name}
				</p>
			{/if}
		{/if}
	{/snippet}
</TraitPanel>
