<script lang="ts">
	import { page } from '$app/stores';
	import { connectionState, nodeStore, edgeStore, nodeVisibility } from '$lib/realtime';
	import type { Node, Edge } from '$lib/realtime';
	import { createNode, createEdge, updateEdge } from '$lib/api';

	const session = $derived($page.data.session as Record<string, unknown> | undefined);
	const nodeId = $derived(session?.nodeId as string | undefined);
	const accessToken = $derived(session?.accessToken as string | undefined);
	const connected = $derived(connectionState.current === 'connected');
	const boardId = $derived($page.params.id ?? '');

	const boardNode = $derived(connected ? nodeStore.get(boardId) : undefined);

	/** Column definitions from board metadata, fallback to defaults */
	const columns = $derived.by(() => {
		if (!boardNode) return ['todo', 'in_progress', 'done'];
		try {
			const meta = JSON.parse(boardNode.metadata ?? '{}');
			const traitConf = meta.traits?.kanban;
			if (traitConf && Array.isArray(traitConf.columns) && traitConf.columns.length > 0) return traitConf.columns as string[];
			// Fallback: legacy metadata.columns path
			if (Array.isArray(meta.columns) && meta.columns.length > 0) return meta.columns as string[];
		} catch { /* ignore */ }
		return ['todo', 'in_progress', 'done'];
	});

	/** Column display labels */
	const columnLabels: Record<string, string> = {
		todo: 'Å gjøre',
		in_progress: 'I gang',
		done: 'Ferdig'
	};

	function columnLabel(col: string): string {
		return columnLabels[col] ?? col;
	}

	/** Column colors for visual distinction */
	const columnColors: Record<string, string> = {
		todo: 'bg-gray-100',
		in_progress: 'bg-blue-50',
		done: 'bg-green-50'
	};

	function columnColor(col: string): string {
		return columnColors[col] ?? 'bg-gray-50';
	}

	/** All cards on this board: nodes with belongs_to edge to board */
	interface CardData {
		node: Node;
		status: string;
		position: number;
		belongsToEdge: Edge;
		statusEdge: Edge | undefined;
	}

	const cards = $derived.by((): CardData[] => {
		if (!connected || !boardId) return [];

		const result: CardData[] = [];

		// Find all nodes with belongs_to edge pointing to this board
		for (const edge of edgeStore.byTarget(boardId)) {
			if (edge.edgeType !== 'belongs_to') continue;

			const node = nodeStore.get(edge.sourceId);
			if (!node || nodeVisibility(node, nodeId) === 'hidden') continue;

			// Find status edge: card --status--> board
			let statusEdge: Edge | undefined;
			let status = columns[0] ?? 'todo'; // default to first column

			for (const e of edgeStore.bySource(node.id)) {
				if (e.edgeType === 'status' && e.targetId === boardId) {
					statusEdge = e;
					try {
						const meta = JSON.parse(e.metadata ?? '{}');
						if (meta.value) status = meta.value;
					} catch { /* ignore */ }
					break;
				}
			}

			// Position from belongs_to edge metadata
			let position = 0;
			try {
				const meta = JSON.parse(edge.metadata ?? '{}');
				if (typeof meta.position === 'number') position = meta.position;
			} catch { /* ignore */ }

			result.push({ node, status, position, belongsToEdge: edge, statusEdge });
		}

		return result;
	});

	/** Cards grouped by column, sorted by position */
	const cardsByColumn = $derived.by(() => {
		const grouped: Record<string, CardData[]> = {};
		for (const col of columns) {
			grouped[col] = [];
		}

		for (const card of cards) {
			const col = columns.includes(card.status) ? card.status : columns[0] ?? 'todo';
			if (!grouped[col]) grouped[col] = [];
			grouped[col].push(card);
		}

		// Sort each column by position
		for (const col of Object.keys(grouped)) {
			grouped[col].sort((a, b) => a.position - b.position);
		}

		return grouped;
	});

	// =========================================================================
	// Drag and drop state
	// =========================================================================

	let draggedCard = $state<CardData | null>(null);
	let dragOverColumn = $state<string | null>(null);

	function handleDragStart(e: DragEvent, card: CardData) {
		draggedCard = card;
		if (e.dataTransfer) {
			e.dataTransfer.effectAllowed = 'move';
			e.dataTransfer.setData('text/plain', card.node.id);
		}
	}

	function handleDragOver(e: DragEvent, column: string) {
		e.preventDefault();
		if (e.dataTransfer) e.dataTransfer.dropEffect = 'move';
		dragOverColumn = column;
	}

	function handleDragLeave() {
		dragOverColumn = null;
	}

	async function handleDrop(e: DragEvent, targetColumn: string) {
		e.preventDefault();
		dragOverColumn = null;

		if (!draggedCard || !accessToken) return;
		if (draggedCard.status === targetColumn) {
			draggedCard = null;
			return;
		}

		const card = draggedCard;
		draggedCard = null;

		try {
			if (card.statusEdge) {
				// Update existing status edge
				await updateEdge(accessToken, {
					edge_id: card.statusEdge.id,
					metadata: { value: targetColumn }
				});
			} else {
				// Create new status edge
				await createEdge(accessToken, {
					source_id: card.node.id,
					target_id: boardId,
					edge_type: 'status',
					metadata: { value: targetColumn }
				});
			}
		} catch (err) {
			console.error('Feil ved statusendring:', err);
		}
	}

	function handleDragEnd() {
		draggedCard = null;
		dragOverColumn = null;
	}

	// =========================================================================
	// Card creation
	// =========================================================================

	let newCardTitle = $state('');
	let addingToColumn = $state<string | null>(null);
	let isCreating = $state(false);

	async function handleCreateCard(column: string) {
		if (!accessToken || !newCardTitle.trim() || isCreating) return;

		isCreating = true;
		try {
			// Calculate position: after last card in column
			const colCards = cardsByColumn[column] ?? [];
			const maxPos = colCards.length > 0
				? Math.max(...colCards.map(c => c.position))
				: 0;
			const position = maxPos + 1;

			// Create the node
			const { node_id } = await createNode(accessToken, {
				node_kind: 'content',
				title: newCardTitle.trim(),
				visibility: 'hidden'
			});

			// Create belongs_to edge with position
			await createEdge(accessToken, {
				source_id: node_id,
				target_id: boardId,
				edge_type: 'belongs_to',
				metadata: { position }
			});

			// Create status edge
			await createEdge(accessToken, {
				source_id: node_id,
				target_id: boardId,
				edge_type: 'status',
				metadata: { value: column }
			});

			newCardTitle = '';
			addingToColumn = null;
		} catch (err) {
			console.error('Feil ved oppretting av kort:', err);
		} finally {
			isCreating = false;
		}
	}

	function handleCardKeydown(e: KeyboardEvent, column: string) {
		if (e.key === 'Enter') {
			e.preventDefault();
			handleCreateCard(column);
		} else if (e.key === 'Escape') {
			addingToColumn = null;
			newCardTitle = '';
		}
	}
</script>

<div class="min-h-screen bg-gray-50">
	<!-- Header -->
	<header class="border-b border-gray-200 bg-white">
		<div class="flex items-center justify-between px-4 py-3">
			<div class="flex items-center gap-3">
				<a href="/" class="text-sm text-gray-400 hover:text-gray-600">&larr; Arbeidsflaten</a>
				<h1 class="text-lg font-semibold text-gray-900">
					{boardNode?.title || 'Kanban-brett'}
				</h1>
			</div>
			<div class="flex items-center gap-3">
				{#if connected}
					<span class="text-xs text-green-600">Tilkoblet</span>
				{:else}
					<span class="text-xs text-gray-400">{connectionState.current}</span>
				{/if}
				<span class="text-xs text-gray-400">{cards.length} kort</span>
			</div>
		</div>
	</header>

	<!-- Board -->
	<main class="overflow-x-auto p-4">
		{#if !connected}
			<p class="text-sm text-gray-400">Venter på tilkobling…</p>
		{:else if !boardNode}
			<div class="rounded-lg border border-yellow-200 bg-yellow-50 p-4 text-sm text-yellow-800">
				Brett ikke funnet. Sjekk at du har tilgang.
			</div>
		{:else}
			<div class="flex gap-4" style="min-width: max-content;">
				{#each columns as column (column)}
					{@const colCards = cardsByColumn[column] ?? []}
					<div
						class="w-72 shrink-0 rounded-lg {columnColor(column)} {dragOverColumn === column ? 'ring-2 ring-blue-400' : ''}"
						ondragover={(e: DragEvent) => handleDragOver(e, column)}
						ondragleave={handleDragLeave}
						ondrop={(e: DragEvent) => handleDrop(e, column)}
						role="list"
						aria-label={columnLabel(column)}
					>
						<!-- Column header -->
						<div class="flex items-center justify-between px-3 py-2">
							<h2 class="text-sm font-semibold text-gray-700">
								{columnLabel(column)}
							</h2>
							<span class="rounded-full bg-white px-2 py-0.5 text-xs text-gray-500 shadow-sm">
								{colCards.length}
							</span>
						</div>

						<!-- Cards -->
						<div class="space-y-2 px-2 pb-2" style="min-height: 2rem;">
							{#each colCards as card (card.node.id)}
								<div
									class="cursor-grab rounded-lg border border-gray-200 bg-white p-3 shadow-sm transition-shadow hover:shadow-md active:cursor-grabbing {draggedCard?.node.id === card.node.id ? 'opacity-50' : ''}"
									draggable="true"
									ondragstart={(e: DragEvent) => handleDragStart(e, card)}
									ondragend={handleDragEnd}
									role="listitem"
								>
									<h3 class="text-sm font-medium text-gray-900">
										{card.node.title || 'Uten tittel'}
									</h3>
									{#if card.node.content}
										<p class="mt-1 text-xs text-gray-500 line-clamp-2">
											{card.node.content}
										</p>
									{/if}
								</div>
							{/each}

							<!-- Add card button/input -->
							{#if addingToColumn === column}
								<div class="rounded-lg border border-blue-300 bg-white p-2">
									<input
										type="text"
										bind:value={newCardTitle}
										onkeydown={(e: KeyboardEvent) => handleCardKeydown(e, column)}
										placeholder="Tittel på nytt kort…"
										class="w-full rounded border border-gray-200 px-2 py-1 text-sm focus:border-blue-400 focus:outline-none"
										disabled={isCreating}
									/>
									<div class="mt-2 flex gap-1">
										<button
											onclick={() => handleCreateCard(column)}
											disabled={isCreating || !newCardTitle.trim()}
											class="rounded bg-blue-600 px-2 py-1 text-xs font-medium text-white hover:bg-blue-700 disabled:opacity-50"
										>
											{isCreating ? 'Oppretter…' : 'Legg til'}
										</button>
										<button
											onclick={() => { addingToColumn = null; newCardTitle = ''; }}
											class="rounded px-2 py-1 text-xs text-gray-500 hover:bg-gray-100"
										>
											Avbryt
										</button>
									</div>
								</div>
							{:else if accessToken}
								<button
									onclick={() => { addingToColumn = column; newCardTitle = ''; }}
									class="w-full rounded-lg p-2 text-left text-sm text-gray-400 hover:bg-white hover:text-gray-600"
								>
									+ Legg til kort
								</button>
							{/if}
						</div>
					</div>
				{/each}
			</div>
		{/if}
	</main>
</div>

<style>
	.line-clamp-2 {
		display: -webkit-box;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
		overflow: hidden;
	}
</style>
