/**
 * Canvas Provider
 *
 * Main orchestrating provider that sets up all canvas context.
 * Combines storage adapter, styles, and graph loading.
 */

import React, { useEffect } from 'react';
import { Provider as JotaiProvider, useSetAtom, useAtomValue } from 'jotai';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { CanvasDbProvider } from '../db/provider';
import { CanvasStyleProvider, type CanvasStyleProviderProps } from './CanvasStyleProvider';
import { currentGraphIdAtom } from '../core/graph-store';
import { loadGraphFromDbAtom } from '../core/graph-mutations';
import type { DBGraphNode, DBGraphEdge } from '../core/types';
import { useGraphNodes } from '../db/hooks/useGraphNodes';
import { useGraphEdges } from '../db/hooks/useGraphEdges';

// Default query client if not provided
const defaultQueryClient = new QueryClient({
	defaultOptions: {
		queries: {
			staleTime: 1000 * 60, // 1 minute
			refetchOnWindowFocus: false,
		},
	},
});

export interface CanvasProviderProps {
	/** Storage adapter */
	adapter: import('../db/adapter').CanvasStorageAdapter;
	/** The graph ID to load */
	graphId: string;
	/** Custom styles */
	styles?: CanvasStyleProviderProps['styles'];
	/** Whether to use dark theme defaults */
	isDark?: boolean;
	/** React Query client (optional, uses default if not provided) */
	queryClient?: QueryClient;
	/** Children */
	children: React.ReactNode;
	/** Callback when graph data loads */
	onGraphLoad?: (nodes: DBGraphNode[], edges: DBGraphEdge[]) => void;
	/** Callback when graph load fails */
	onGraphError?: (error: Error) => void;
}

/**
 * Internal component that handles graph loading
 */
function GraphLoader({
	graphId,
	onGraphLoad,
	onGraphError,
	children,
}: {
	graphId: string;
	onGraphLoad?: (nodes: DBGraphNode[], edges: DBGraphEdge[]) => void;
	onGraphError?: (error: Error) => void;
	children: React.ReactNode;
}) {
	const setCurrentGraphId = useSetAtom(currentGraphIdAtom);
	const loadGraphFromDb = useSetAtom(loadGraphFromDbAtom);

	// Fetch nodes and edges
	const { data: nodes, error: nodesError, isLoading: nodesLoading } = useGraphNodes(graphId);
	const { data: edges, error: edgesError, isLoading: edgesLoading } = useGraphEdges(graphId);

	// Set current graph ID
	useEffect(() => {
		setCurrentGraphId(graphId);
	}, [graphId, setCurrentGraphId]);

	// Load graph data when available
	useEffect(() => {
		if (nodes && edges && !nodesLoading && !edgesLoading) {
			loadGraphFromDb(nodes, edges);
			onGraphLoad?.(nodes, edges);
		}
	}, [nodes, edges, nodesLoading, edgesLoading, loadGraphFromDb, onGraphLoad]);

	// Handle errors
	useEffect(() => {
		const error = nodesError || edgesError;
		if (error) {
			onGraphError?.(error as Error);
		}
	}, [nodesError, edgesError, onGraphError]);

	return <>{children}</>;
}

/**
 * Main Canvas Provider
 *
 * Sets up all necessary context for the canvas:
 * - Jotai store
 * - React Query client
 * - Storage adapter
 * - Canvas styles
 * - Graph loading
 *
 * @example
 * ```tsx
 * <CanvasProvider
 *   adapter={new SupabaseStorageAdapter(supabaseClient)}
 *   graphId={graphId}
 *   styles={customStyles}
 *   isDark={theme === 'dark'}
 * >
 *   <Canvas renderNode={({ node }) => <MyNodeContent node={node} />} />
 * </CanvasProvider>
 * ```
 */
export function CanvasProvider({
	adapter,
	graphId,
	styles,
	isDark = false,
	queryClient = defaultQueryClient,
	children,
	onGraphLoad,
	onGraphError,
}: CanvasProviderProps) {
	return (
		<JotaiProvider>
			<QueryClientProvider client={queryClient}>
				<CanvasDbProvider adapter={adapter}>
					<CanvasStyleProvider styles={styles} isDark={isDark}>
						<GraphLoader graphId={graphId} onGraphLoad={onGraphLoad} onGraphError={onGraphError}>
							{children}
						</GraphLoader>
					</CanvasStyleProvider>
				</CanvasDbProvider>
			</QueryClientProvider>
		</JotaiProvider>
	);
}

