/**
 * Chat store - manages WebSocket connection and chat state
 */

const isBrowser = typeof window !== 'undefined';

export interface ChatConversation {
	id: string;
	title: string;
	created_at: string;
	updated_at?: string;
}

export interface ToolCall {
	id: string;
	name: string;
	input: Record<string, unknown>;
}

export interface ToolResult {
	tool_use_id: string;
	result: unknown;
}

export interface ChatMessage {
	id: string;
	role: 'user' | 'assistant';
	content: string;
	tool_calls?: ToolCall[];
	tool_results?: ToolResult[];
	created_at: string;
}

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

function createChatStore() {
	// Connection state
	let ws: WebSocket | null = null;
	let connectionStatus = $state<ConnectionStatus>('disconnected');
	let reconnectAttempts = 0;
	const maxReconnectAttempts = 5;
	let reconnectTimeout: ReturnType<typeof setTimeout> | null = null;

	// UI state
	let isOpen = $state(false);
	let isStreaming = $state(false);

	// Data state
	let conversations = $state<ChatConversation[]>([]);
	let activeConversationId = $state<string | null>(null);
	let messages = $state<ChatMessage[]>([]);
	let streamingContent = $state('');
	let currentToolCalls = $state<ToolCall[]>([]);
	let user = $state<{ id: string; name: string; email: string } | null>(null);
	let introMessage = $state<string | null>(null);

	// Derive active conversation
	const activeConversation = $derived(
		conversations.find((c) => c.id === activeConversationId) ?? null
	);

	function getWebSocketUrl(): string {
		// In development, connect directly to Django
		// In production, go through the proxy
		if (isBrowser) {
			const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
			// Replace app. or admin. with api. for the backend
			const host = window.location.host.replace(/^(app|admin)\./, 'api.');
			return `${protocol}//${host}/v1/ws/chat/`;
		}
		return '';
	}

	function connect(): void {
		if (!isBrowser || ws?.readyState === WebSocket.OPEN) return;

		connectionStatus = 'connecting';

		try {
			ws = new WebSocket(getWebSocketUrl());

			ws.onopen = () => {
				connectionStatus = 'connected';
				reconnectAttempts = 0;
				// Request conversation list
				send({ type: 'conversations' });
			};

			ws.onmessage = (event) => {
				try {
					const data = JSON.parse(event.data);
					handleMessage(data);
				} catch (e) {
					console.error('Failed to parse WebSocket message:', e);
				}
			};

			ws.onclose = (event) => {
				connectionStatus = 'disconnected';
				ws = null;

				// Attempt reconnection if not a normal close
				if (event.code !== 1000 && reconnectAttempts < maxReconnectAttempts) {
					const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);
					reconnectTimeout = setTimeout(() => {
						reconnectAttempts++;
						connect();
					}, delay);
				}
			};

			ws.onerror = () => {
				connectionStatus = 'error';
			};
		} catch (e) {
			console.error('Failed to create WebSocket:', e);
			connectionStatus = 'error';
		}
	}

	function disconnect(): void {
		if (reconnectTimeout) {
			clearTimeout(reconnectTimeout);
			reconnectTimeout = null;
		}
		if (ws) {
			ws.close(1000);
			ws = null;
		}
		connectionStatus = 'disconnected';
	}

	function send(data: Record<string, unknown>): void {
		if (ws?.readyState === WebSocket.OPEN) {
			ws.send(JSON.stringify(data));
		}
	}

	function handleMessage(data: Record<string, unknown>): void {
		const type = data.type as string;

		switch (type) {
			case 'connected':
				user = data.user as { id: string; name: string; email: string };
				break;

			case 'intro':
				introMessage = data.content as string;
				break;

			case 'conversations':
				conversations = data.conversations as ChatConversation[];
				break;

			case 'conversation_created':
				{
					const conv = data.conversation as ChatConversation;
					conversations = [conv, ...conversations];
					activeConversationId = conv.id;
				}
				break;

			case 'history':
				{
					const historyData = data.conversation as {
						id: string;
						messages: ChatMessage[];
					};
					messages = historyData.messages;
				}
				break;

			case 'user_message':
				{
					const userMsg = data.message as ChatMessage;
					messages = [...messages, userMsg];
				}
				break;

			case 'stream_start':
				isStreaming = true;
				streamingContent = '';
				currentToolCalls = [];
				break;

			case 'content_delta':
				streamingContent += data.content as string;
				break;

			case 'tool_use':
				currentToolCalls = [...currentToolCalls, data.tool as ToolCall];
				break;

			case 'tool_result':
				// Tool results are handled as part of the message
				break;

			case 'stream_end':
				{
					isStreaming = false;
					const assistantMsg = data.message as ChatMessage;
					messages = [...messages, assistantMsg];
					streamingContent = '';
					currentToolCalls = [];

					// Update conversation title if provided
					if (data.title && activeConversationId) {
						conversations = conversations.map((c) =>
							c.id === activeConversationId ? { ...c, title: data.title as string } : c
						);
					}
				}
				break;

			case 'error':
				console.error('Chat error:', data.error);
				isStreaming = false;
				break;
		}
	}

	function sendMessage(content: string): void {
		if (!content.trim() || isStreaming) return;

		send({
			type: 'chat',
			content: content.trim(),
			conversation_id: activeConversationId
		});
	}

	function selectConversation(conversationId: string): void {
		if (conversationId === activeConversationId) return;

		activeConversationId = conversationId;
		messages = [];

		// Request history for this conversation
		send({
			type: 'history',
			conversation_id: conversationId
		});
	}

	function startNewConversation(): void {
		activeConversationId = null;
		messages = [];
	}

	function toggle(): void {
		isOpen = !isOpen;
		if (isOpen && connectionStatus === 'disconnected') {
			connect();
		}
	}

	function open(): void {
		isOpen = true;
		if (connectionStatus === 'disconnected') {
			connect();
		}
	}

	function close(): void {
		isOpen = false;
	}

	return {
		// Connection
		get connectionStatus() {
			return connectionStatus;
		},
		connect,
		disconnect,

		// UI
		get isOpen() {
			return isOpen;
		},
		get isStreaming() {
			return isStreaming;
		},
		toggle,
		open,
		close,

		// Data
		get user() {
			return user;
		},
		get conversations() {
			return conversations;
		},
		get activeConversation() {
			return activeConversation;
		},
		get activeConversationId() {
			return activeConversationId;
		},
		get messages() {
			return messages;
		},
		get streamingContent() {
			return streamingContent;
		},
		get currentToolCalls() {
			return currentToolCalls;
		},
		get introMessage() {
			return introMessage;
		},

		// Actions
		sendMessage,
		selectConversation,
		startNewConversation
	};
}

export const chat = createChatStore();
