/**
 * WebSocket-tilkobling til portvokteren (maskinrommet).
 *
 * Kobler til /ws-endepunktet,
 * mottar initial_sync og inkrementelle events, og oppdaterer reactive stores.
 *
 * Usage:
 *   import { wsConnect, wsDisconnect, connectionState } from '$lib/realtime/connection.svelte';
 */

import { page } from '$app/stores';
import { get } from 'svelte/store';
import type { WsMessage } from './types';
import {
	nodeStore,
	edgeStore,
	nodeAccessStore,
	mixerChannelStore,
	handleInitialSync,
	clearAllStores,
} from './stores.svelte';

export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'error';

let ws: WebSocket | null = null;
let _state = $state<ConnectionState>('disconnected');
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;

/** Reactive connection state. */
export const connectionState = {
	get current() {
		return _state;
	},
};

/**
 * Koble til portvokterens WebSocket-endepunkt.
 */
export function wsConnect(accessToken: string) {
	if (ws) return;

	const apiBase = import.meta.env.VITE_API_URL ?? '/api';
	let wsUrl: string;

	if (apiBase.startsWith('http')) {
		wsUrl = apiBase.replace(/^http/, 'ws') + '/ws';
	} else {
		const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
		wsUrl = `${proto}//${window.location.host}${apiBase}/ws`;
	}

	wsUrl += `?token=${encodeURIComponent(accessToken)}`;

	_state = 'connecting';
	console.log('[ws] Kobler til portvokteren...');

	ws = new WebSocket(wsUrl);

	ws.onopen = () => {
		console.log('[ws] Tilkoblet');
		_state = 'connected';
	};

	ws.onmessage = (event) => {
		try {
			const msg: WsMessage = JSON.parse(event.data);

			switch (msg.type) {
				case 'initial_sync':
					console.log(
						`[ws] Initial sync: ${msg.nodes?.length ?? 0} noder, ` +
							`${msg.edges?.length ?? 0} edges, ${msg.access?.length ?? 0} access, ` +
							`${msg.mixer_channels?.length ?? 0} mixer`,
					);
					handleInitialSync(msg);
					break;
				case 'node_changed':
					nodeStore._handleEvent(msg);
					break;
				case 'edge_changed':
					edgeStore._handleEvent(msg);
					break;
				case 'access_changed':
					nodeAccessStore._handleEvent(msg);
					break;
				case 'mixer_channel_changed':
					mixerChannelStore._handleEvent(msg);
					break;
			}
		} catch {
			console.warn('[ws] Ikke-JSON-melding:', event.data);
		}
	};

	ws.onerror = (event) => {
		console.error('[ws] Feil:', event);
		_state = 'error';
	};

	ws.onclose = (event) => {
		console.log('[ws] Frakoblet:', event.code, event.reason);
		ws = null;
		_state = 'disconnected';
		clearAllStores();

		// Auto-reconnect etter 3 sekunder
		if (!reconnectTimer) {
			reconnectTimer = setTimeout(() => {
				reconnectTimer = null;
				const session = get(page)?.data?.session as Record<string, unknown> | undefined;
				const token = session?.accessToken as string | undefined;
				if (token) {
					console.log('[ws] Automatisk gjenoppkobling...');
					wsConnect(token);
				}
			}, 3000);
		}
	};
}

/** Koble fra WebSocket. */
export function wsDisconnect() {
	if (reconnectTimer) {
		clearTimeout(reconnectTimer);
		reconnectTimer = null;
	}
	if (ws) {
		ws.close();
		ws = null;
		_state = 'disconnected';
		clearAllStores();
	}
}
