<script lang="ts">
	/**
	 * Node Explorer — utforsk og rediger noder i grafen.
	 */
	import { nodeStore, edgeStore } from '$lib/realtime';
	import type { Node } from '$lib/realtime';
	import { updateNode } from '$lib/api';

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

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

	let searchQuery = $state('');
	let filterKind = $state('');
	let selectedNodeId = $state<string | undefined>(undefined);
	let limit = $state(50);

	// Reaktiv: følger nodeStore slik at endringer reflekteres umiddelbart
	const selectedNode = $derived(selectedNodeId ? nodeStore.get(selectedNodeId) : undefined);

	// Kan brukeren redigere denne noden?
	const canEdit = $derived(
		selectedNode && userId && (
			selectedNode.createdBy === userId ||
			userId === 'd3eebc99-9c0b-4ef8-bb6d-6bb9bd380a44' // TODO: ekte admin-sjekk
		)
	);

	// Editing state
	let editing = $state(false);
	let editTitle = $state('');
	let editContent = $state('');
	let editMetadata = $state('');
	let saving = $state(false);
	let saveError = $state('');

	const nodeKinds = $derived.by(() => {
		const kinds = new Set<string>();
		for (const node of nodeStore.all) {
			kinds.add(node.nodeKind);
		}
		return [...kinds].sort();
	});

	const results = $derived.by(() => {
		let nodes = [...nodeStore.all];
		if (filterKind) {
			nodes = nodes.filter(n => n.nodeKind === filterKind);
		}
		if (searchQuery.trim()) {
			const q = searchQuery.toLowerCase().trim();
			nodes = nodes.filter(n =>
				(n.title ?? '').toLowerCase().includes(q) ||
				(n.content ?? '').toLowerCase().includes(q) ||
				n.id.toLowerCase().includes(q) ||
				n.nodeKind.toLowerCase().includes(q)
			);
		}
		nodes.sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0));
		return nodes.slice(0, limit);
	});

	const totalCount = $derived(nodeStore.count);

	const selectedEdgesOut = $derived.by(() => {
		if (!selectedNode) return [];
		return edgeStore.bySource(selectedNode.id);
	});

	const selectedEdgesIn = $derived.by(() => {
		if (!selectedNode) return [];
		return edgeStore.byTarget(selectedNode.id);
	});

	function selectNode(node: Node) {
		selectedNodeId = node.id;
		editing = false;
		saveError = '';
	}

	function navigateToNode(id: string) {
		selectedNodeId = id;
		editing = false;
		saveError = '';
	}

	function startEditing() {
		if (!selectedNode) return;
		editTitle = selectedNode.title || '';
		editContent = selectedNode.content || '';
		editMetadata = parseMetadata(selectedNode.metadata);
		editing = true;
		saveError = '';
	}

	async function saveEdits() {
		if (!selectedNode || !accessToken) return;
		saving = true;
		saveError = '';
		try {
			// Validér metadata JSON
			let metadataObj: Record<string, unknown> | undefined;
			if (editMetadata.trim() && editMetadata.trim() !== '{}') {
				metadataObj = JSON.parse(editMetadata);
			}

			await updateNode(accessToken, {
				node_id: selectedNode.id,
				title: editTitle,
				content: editContent,
				...(metadataObj !== undefined ? { metadata: metadataObj } : {}),
			});
			editing = false;
		} catch (e) {
			saveError = String(e);
		} finally {
			saving = false;
		}
	}

	function cancelEditing() {
		editing = false;
		saveError = '';
	}

	function formatDate(ts: number | undefined): string {
		if (!ts) return '—';
		return new Date(ts).toLocaleString('no-NO', {
			day: '2-digit', month: '2-digit', year: '2-digit',
			hour: '2-digit', minute: '2-digit'
		});
	}

	function truncate(s: string | undefined, max: number): string {
		if (!s) return '';
		return s.length > max ? s.slice(0, max) + '…' : s;
	}

	function parseMetadata(s: string | undefined): string {
		if (!s) return '{}';
		try {
			return JSON.stringify(JSON.parse(s), null, 2);
		} catch {
			return s;
		}
	}
</script>

<div class="ne">
	<!-- Søk og filter -->
	<div class="ne-toolbar">
		<div class="ne-search-wrap">
			<input
				class="ne-search"
				type="text"
				placeholder="Søk noder..."
				bind:value={searchQuery}
			/>
			{#if searchQuery}
				<button class="ne-clear" onclick={() => { searchQuery = ''; }} title="Tøm søk">✕</button>
			{/if}
		</div>
		<div class="ne-filter-wrap">
			<select class="ne-filter" bind:value={filterKind}>
				<option value="">Alle ({totalCount})</option>
				{#each nodeKinds as kind (kind)}
					<option value={kind}>{kind}</option>
				{/each}
			</select>
			{#if filterKind}
				<button class="ne-clear" onclick={() => { filterKind = ''; }} title="Vis alle typer">✕</button>
			{/if}
		</div>
	</div>

	<div class="ne-body">
		<!-- Resultat-liste -->
		<div class="ne-list">
			{#each results as node (node.id)}
				<button
					class="ne-item"
					class:ne-item-selected={selectedNode?.id === node.id}
					onclick={() => selectNode(node)}
				>
					<div class="ne-item-header">
						<span class="ne-item-kind">{node.nodeKind}</span>
						<span class="ne-item-date">{formatDate(node.createdAt)}</span>
					</div>
					<div class="ne-item-title">{node.title || node.id.slice(0, 8)}</div>
					{#if node.content}
						<div class="ne-item-excerpt">{truncate(node.content, 80)}</div>
					{/if}
				</button>
			{/each}
			{#if results.length === 0}
				<div class="ne-empty">Ingen noder funnet</div>
			{/if}
			{#if results.length >= limit}
				<button class="ne-more" onclick={() => { limit += 50; }}>
					Vis flere...
				</button>
			{/if}
		</div>

		<!-- Detaljer / redigering -->
		{#if selectedNode}
			<div class="ne-detail">
				<div class="ne-detail-header">
					<span class="ne-detail-kind">{selectedNode.nodeKind}</span>
					<div class="ne-detail-actions">
						{#if !editing && canEdit}
							<button class="ne-action-btn" onclick={startEditing} title="Rediger">✏️</button>
						{/if}
					</div>
				</div>
				<div class="ne-detail-id">{selectedNode.id}</div>

				{#if editing}
					<!-- Redigeringsmodus -->
					<div class="ne-edit-section">
						<div class="ne-detail-label">Tittel</div>
						<input class="ne-edit-input" bind:value={editTitle} />
					</div>
					<div class="ne-edit-section">
						<div class="ne-detail-label">Innhold</div>
						<textarea class="ne-edit-textarea" bind:value={editContent} rows="6"></textarea>
					</div>
					<div class="ne-edit-section">
						<div class="ne-detail-label">Metadata (JSON)</div>
						<textarea class="ne-edit-textarea ne-edit-mono" bind:value={editMetadata} rows="8"></textarea>
					</div>
					{#if saveError}
						<div class="ne-error">{saveError}</div>
					{/if}
					<div class="ne-edit-actions">
						<button class="ne-save-btn" onclick={saveEdits} disabled={saving}>
							{saving ? 'Lagrer...' : 'Lagre'}
						</button>
						<button class="ne-cancel-btn" onclick={cancelEditing}>Avbryt</button>
					</div>
				{:else}
					<!-- Visningsmodus -->
					<h3 class="ne-detail-title">{selectedNode.title || 'Uten tittel'}</h3>

					<div class="ne-detail-meta">
						<div>Opprettet: {formatDate(selectedNode.createdAt)}</div>
						<div>Av: {selectedNode.createdBy?.slice(0, 8) ?? '—'}</div>
						<div>Synlighet: {selectedNode.visibility}</div>
					</div>

					{#if selectedNode.content}
						<div class="ne-detail-section">
							<div class="ne-detail-label">Innhold</div>
							<pre class="ne-detail-content">{truncate(selectedNode.content, 500)}</pre>
						</div>
					{/if}

					{#if selectedNode.metadata && selectedNode.metadata !== '{}'}
						<div class="ne-detail-section">
							<div class="ne-detail-label">Metadata</div>
							<pre class="ne-detail-content">{parseMetadata(selectedNode.metadata)}</pre>
						</div>
					{/if}

					{#if selectedEdgesOut.length > 0}
						<div class="ne-detail-section">
							<div class="ne-detail-label">Edges ut ({selectedEdgesOut.length})</div>
							{#each selectedEdgesOut as edge (edge.id)}
								<button class="ne-edge" onclick={() => navigateToNode(edge.targetId)}>
									<span class="ne-edge-type">→ {edge.edgeType}</span>
									<span class="ne-edge-target">
										{nodeStore.get(edge.targetId)?.title || edge.targetId.slice(0, 8)}
									</span>
									{#if edge.system}<span class="ne-edge-system">system</span>{/if}
								</button>
							{/each}
						</div>
					{/if}

					{#if selectedEdgesIn.length > 0}
						<div class="ne-detail-section">
							<div class="ne-detail-label">Edges inn ({selectedEdgesIn.length})</div>
							{#each selectedEdgesIn as edge (edge.id)}
								<button class="ne-edge" onclick={() => navigateToNode(edge.sourceId)}>
									<span class="ne-edge-type">← {edge.edgeType}</span>
									<span class="ne-edge-target">
										{nodeStore.get(edge.sourceId)?.title || edge.sourceId.slice(0, 8)}
									</span>
									{#if edge.system}<span class="ne-edge-system">system</span>{/if}
								</button>
							{/each}
						</div>
					{/if}
				{/if}
			</div>
		{:else}
			<div class="ne-detail ne-detail-empty">
				Velg en node for å se detaljer
			</div>
		{/if}
	</div>
</div>

<style>
	.ne { display: flex; flex-direction: column; height: 100%; overflow: hidden; }

	.ne-toolbar {
		display: flex; gap: 6px; padding: 8px;
		border-bottom: 1px solid var(--color-border, #2a2a2e);
	}
	.ne-search-wrap, .ne-filter-wrap {
		position: relative; display: flex; align-items: center;
	}
	.ne-search-wrap { flex: 1; }
	.ne-search {
		width: 100%; padding: 6px 28px 6px 10px; border-radius: 6px; font-size: 13px;
	}
	.ne-filter {
		width: 140px; padding: 6px 24px 6px 8px; border-radius: 6px; font-size: 12px;
		cursor: pointer;
	}
	.ne-filter-wrap .ne-clear {
		right: 22px;
	}
	.ne-clear {
		position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
		border: none; background: transparent; cursor: pointer;
		font-size: 12px; color: var(--color-text-dim, #5a5a66);
		padding: 2px 4px; border-radius: 3px; line-height: 1;
	}
	.ne-clear:hover { color: var(--color-text, #e8e8ec); background: var(--color-surface-hover, #242428); }

	.ne-body { display: flex; flex: 1; min-height: 0; overflow: hidden; }

	.ne-list {
		width: 45%; overflow-y: auto; border-right: 1px solid var(--color-border, #2a2a2e);
	}
	.ne-item {
		display: block; width: 100%; padding: 8px 10px; border: none;
		background: transparent; text-align: left; cursor: pointer;
		border-bottom: 1px solid var(--color-border, #2a2a2e);
		font-size: 12px; color: var(--color-text-muted, #8a8a96);
		transition: background 0.1s;
	}
	.ne-item:hover { background: var(--color-surface-hover, #242428); }
	.ne-item-selected { background: var(--color-accent-glow, rgba(99,102,241,0.15)); }
	.ne-item-header { display: flex; justify-content: space-between; margin-bottom: 2px; }
	.ne-item-kind {
		font-size: 10px; font-weight: 600; text-transform: uppercase;
		color: var(--color-accent, #6366f1); letter-spacing: 0.03em;
	}
	.ne-item-date { font-size: 10px; color: var(--color-text-dim, #5a5a66); }
	.ne-item-title { font-size: 13px; font-weight: 500; color: var(--color-text, #e8e8ec); }
	.ne-item-excerpt { font-size: 11px; color: var(--color-text-dim, #5a5a66); margin-top: 2px; }

	.ne-detail { width: 55%; overflow-y: auto; padding: 10px; }
	.ne-detail-empty {
		display: flex; align-items: center; justify-content: center; height: 100%;
		color: var(--color-text-dim, #5a5a66); font-size: 13px;
	}
	.ne-detail-header {
		display: flex; justify-content: space-between; align-items: center; margin-bottom: 2px;
	}
	.ne-detail-kind {
		font-size: 11px; font-weight: 600; text-transform: uppercase;
		color: var(--color-accent, #6366f1); letter-spacing: 0.03em;
	}
	.ne-detail-actions { display: flex; gap: 4px; }
	.ne-action-btn {
		border: none; background: var(--color-surface-hover, #242428);
		cursor: pointer; padding: 3px 8px; border-radius: 4px; font-size: 12px;
		transition: background 0.1s;
	}
	.ne-action-btn:hover { background: var(--color-border, #2a2a2e); }
	.ne-detail-id { font-size: 10px; color: var(--color-text-dim, #5a5a66); font-family: monospace; margin-bottom: 6px; }
	.ne-detail-title { font-size: 16px; font-weight: 600; color: var(--color-text, #e8e8ec); margin-bottom: 8px; }
	.ne-detail-meta { font-size: 11px; color: var(--color-text-dim, #5a5a66); margin-bottom: 10px; line-height: 1.6; }

	.ne-detail-section { margin-bottom: 12px; }
	.ne-detail-label {
		font-size: 10px; font-weight: 600; text-transform: uppercase;
		color: var(--color-text-dim, #5a5a66); letter-spacing: 0.05em; margin-bottom: 4px;
	}
	.ne-detail-content {
		font-size: 11px; font-family: monospace; white-space: pre-wrap; word-break: break-all;
		background: var(--color-bg, #0a0a0b); border: 1px solid var(--color-border, #2a2a2e);
		border-radius: 4px; padding: 8px; max-height: 200px; overflow-y: auto;
		color: var(--color-text-muted, #8a8a96);
	}

	.ne-edge {
		display: flex; align-items: center; gap: 6px; width: 100%;
		padding: 4px 8px; border: none; background: transparent;
		cursor: pointer; font-size: 12px; color: var(--color-text-muted, #8a8a96);
		border-radius: 4px; text-align: left; transition: background 0.1s;
	}
	.ne-edge:hover { background: var(--color-surface-hover, #242428); }
	.ne-edge-type { font-weight: 500; min-width: 100px; color: var(--color-accent, #6366f1); }
	.ne-edge-target { flex: 1; }
	.ne-edge-system { font-size: 10px; color: var(--color-text-dim, #5a5a66); }

	.ne-empty { padding: 20px; text-align: center; font-size: 13px; color: var(--color-text-dim, #5a5a66); }
	.ne-more {
		width: 100%; padding: 8px; border: none; background: transparent;
		cursor: pointer; font-size: 12px; color: var(--color-accent, #6366f1);
	}
	.ne-more:hover { background: var(--color-surface-hover, #242428); }

	/* Editing */
	.ne-edit-section { margin-bottom: 10px; }
	.ne-edit-input {
		width: 100%; padding: 6px 8px; border-radius: 4px; font-size: 14px; font-weight: 500;
	}
	.ne-edit-textarea {
		width: 100%; padding: 6px 8px; border-radius: 4px; font-size: 12px;
		resize: vertical; min-height: 60px;
	}
	.ne-edit-mono { font-family: monospace; font-size: 11px; }
	.ne-edit-actions { display: flex; gap: 6px; margin-top: 8px; }
	.ne-save-btn {
		padding: 5px 14px; border: none; border-radius: 4px; font-size: 12px;
		background: var(--color-accent, #6366f1); color: white; cursor: pointer;
	}
	.ne-save-btn:hover { background: var(--color-accent-hover, #7577f5); }
	.ne-save-btn:disabled { opacity: 0.5; cursor: default; }
	.ne-cancel-btn {
		padding: 5px 14px; border: none; border-radius: 4px; font-size: 12px;
		background: var(--color-surface-hover, #242428); color: var(--color-text-muted, #8a8a96); cursor: pointer;
	}
	.ne-cancel-btn:hover { background: var(--color-border, #2a2a2e); }
	.ne-error {
		font-size: 11px; color: var(--color-error, #ef4444); margin-top: 6px;
		padding: 4px 8px; background: rgba(239, 68, 68, 0.1); border-radius: 4px;
	}
</style>
