import { useEffect, useRef, useState } from 'react';
import { useNavigate, useLocation } from 'react-router';
import {
    Tldraw,
    Editor,
    useTldrawUser,
    DEFAULT_SUPPORT_VIDEO_TYPES,
    DEFAULT_SUPPORTED_IMAGE_TYPES,
    TLStore,
    TLStoreWithStatus
} from '@tldraw/tldraw';
import { useTLDraw } from '../../contexts/TLDrawContext';
import { useUser } from '../../contexts/UserContext';
// Tldraw services
import { localStoreService } from '../../services/tldraw/localStoreService';
import { PresentationService } from '../../services/tldraw/presentationService';
import { UserNeoDBService } from '../../services/graph/userNeoDBService';
import { NodeCanvasService } from '../../services/tldraw/nodeCanvasService';
import { NavigationSnapshotService } from '../../services/tldraw/snapshotService';
// Tldraw utils
import { getUiOverrides, getUiComponents } from '../../utils/tldraw/ui-overrides';
import { customAssets } from '../../utils/tldraw/assets';
import { singlePlayerTools } from '../../utils/tldraw/tools';
import { allShapeUtils } from '../../utils/tldraw/shapes';
import { allBindingUtils } from '../../utils/tldraw/bindings';
import { singlePlayerEmbeds } from '../../utils/tldraw/embeds';
import { customSchema } from '../../utils/tldraw/schemas';
// Navigation
import { useNavigationStore } from '../../stores/navigationStore';
// Layout
import { HEADER_HEIGHT } from '../../pages/Layout';
// Styles
import '../../utils/tldraw/tldraw.css';
// App debug
import { logger } from '../../debugConfig';
import { CircularProgress, Alert, Snackbar } from '@mui/material';
import { getThemeFromLabel } from '../../utils/tldraw/cc-base/cc-graph/cc-graph-styles';
import { NodeData } from '../../types/graph-shape';
import { NavigationNode } from '../../types/navigation';

interface LoadingState {
    status: 'ready' | 'loading' | 'error';
    error: string;
}

export default function SinglePlayerPage() {
    // Context hooks with initialization states
    const { profile: user, loading: userLoading } = useUser();
    const { 
        tldrawPreferences, 
        initializePreferences,
        presentationMode,
        setTldrawPreferences
    } = useTLDraw();
    const routerNavigate = useNavigate();
    const location = useLocation();

    // Navigation store
    const { context } = useNavigationStore();

    // Refs
    const editorRef = useRef<Editor | null>(null);
    const snapshotServiceRef = useRef<NavigationSnapshotService | null>(null);

    // State
    const [loadingState, setLoadingState] = useState<LoadingState>({ 
        status: 'ready', 
        error: '' 
    });
    const [isInitialLoad, setIsInitialLoad] = useState(true);
    const [isEditorReady, setIsEditorReady] = useState(false);
    const [store, setStore] = useState<TLStore | TLStoreWithStatus | undefined>(undefined);

    // TLDraw user preferences
    const tldrawUser = useTldrawUser({
        userPreferences: {
            id: user?.id ?? '',
            name: user?.display_name,
            color: tldrawPreferences?.color,
            locale: tldrawPreferences?.locale,
            colorScheme: tldrawPreferences?.colorScheme,
            animationSpeed: tldrawPreferences?.animationSpeed,
            isSnapMode: tldrawPreferences?.isSnapMode
        },
        setUserPreferences: setTldrawPreferences
    });

    // Initialize store — runs as soon as user is ready, no editor needed for store creation
    useEffect(() => {
        if (!user) {
            logger.debug('single-player-page', '⏳ Waiting for user data');
            return;
        }

        logger.info('single-player-page', '🔄 Starting store initialization', {
            isEditorReady,
            hasUser: !!user,
            userType: user.user_type,
            username: user.username
        });

        const initializeStoreAndSnapshot = async () => {
            try {
                setLoadingState({ status: 'loading', error: '' });
                
                // 1. Create store
                logger.debug('single-player-page', '🔄 Creating TLStore');
                const newStore = localStoreService.getStore({
                    schema: customSchema,
                    shapeUtils: allShapeUtils,
                    bindingUtils: allBindingUtils
                });
                logger.debug('single-player-page', '✅ TLStore created');

                // 2. Initialize snapshot service
                const snapshotService = new NavigationSnapshotService(newStore, editorRef.current || undefined);
                snapshotServiceRef.current = snapshotService;
                logger.debug('single-player-page', '✨ Initialized NavigationSnapshotService');

                // 3. Load initial snapshot if we have a node
                if (context.node) {
                    const nodeStoragePath = getNodeStoragePath(context.node);
                    if (nodeStoragePath) {
                        logger.debug('single-player-page', '📥 Loading snapshot from database', { 
                            dbName: user.user_db_name,
                            node: context.node,
                            node_storage_path: nodeStoragePath,
                            user_type: user.user_type,
                            username: user.username
                        });

                        await NavigationSnapshotService.loadNodeSnapshotFromDatabase(
                            nodeStoragePath,
                            user.user_db_name,
                            newStore,
                            setLoadingState,
                            undefined, // sharedStore
                            editorRef.current || undefined // editor
                        );
                        logger.debug('single-player-page', '✅ Snapshot loaded from database');
                    } else {
                        logger.debug('single-player-page', '⚠️ No node_storage_path found in node, skipping snapshot load', {
                            node: context.node
                        });
                    }
                } else {
                    logger.debug('single-player-page', '⚠️ No node in context, skipping snapshot load');
                }

                // 4. Set up auto-save with debouncing (only after initial load is complete)
                let autoSaveTimeout: ReturnType<typeof setTimeout> | null = null;
                let isAutoSaving = false;
                
                newStore.listen(() => {
                    if (snapshotServiceRef.current && context.node && snapshotServiceRef.current.getCurrentNodePath()) {
                        // Skip if already saving
                        if (isAutoSaving) {
                            logger.debug('single-player-page', '⚠️ Skipping auto-save - already saving');
                            return;
                        }
                        
                        // Clear existing timeout
                        if (autoSaveTimeout) {
                            clearTimeout(autoSaveTimeout);
                        }
                        
                        // Debounce auto-save to prevent excessive saves
                        autoSaveTimeout = setTimeout(async () => {
                            if (isAutoSaving) return; // Double-check
                            
                            isAutoSaving = true;
                            try {
                                logger.debug('single-player-page', '💾 Auto-saving changes (debounced)');
                                await snapshotServiceRef.current?.forceSaveCurrentNode();
                            } catch (error) {
                                logger.error('single-player-page', '❌ Auto-save failed', error);
                            } finally {
                                isAutoSaving = false;
                            }
                        }, 2000); // Increased to 2 seconds debounce
                    } else if (snapshotServiceRef.current && context.node && !snapshotServiceRef.current.getCurrentNodePath()) {
                        logger.debug('single-player-page', '⚠️ Skipping auto-save - no current node path set yet');
                    }
                });

                // 5. Update store state
                setStore(newStore);
                setLoadingState({ status: 'ready', error: '' });
                logger.info('single-player-page', '✅ Store initialization complete');

                // 6. Handle cleanup
                return () => {
                    logger.debug('single-player-page', '🧹 Starting cleanup');
                    if (snapshotServiceRef.current) {
                        snapshotServiceRef.current.forceSaveCurrentNode().catch(error => {
                            logger.error('single-player-page', '❌ Final save failed', error);
                        });
                        snapshotServiceRef.current.clearCurrentNode();
                        snapshotServiceRef.current = null;
                    }
                    newStore.dispose();
                    setStore(undefined);
                    logger.debug('single-player-page', '🧹 Cleanup complete');
                };
            } catch (error) {
                const errorMessage = error instanceof Error ? error.message : 'Failed to initialize store';
                logger.error('single-player-page', '❌ Store initialization failed', error);
                setLoadingState({ status: 'error', error: errorMessage });
                return undefined;
            }
        };

        initializeStoreAndSnapshot();
    }, [user, context.node]);

    // Handle initial node placement
    useEffect(() => {
        const placeInitialNode = async () => {
            if (!context.node || !editorRef.current || !store || !isInitialLoad) {
                logger.debug('single-player-page', '⚠️ Skipping placeInitialNode - missing dependencies', {
                    hasNode: !!context.node,
                    hasEditor: !!editorRef.current,
                    hasStore: !!store,
                    isInitialLoad
                });
                return;
            }

            // Debug: Log the actual node structure
            logger.debug('single-player-page', '🔍 Node structure for placeInitialNode', {
                node: context.node,
                nodeKeys: Object.keys(context.node),
                hasId: !!context.node.id,
                hasStoragePath: !!context.node.node_storage_path,
                hasData: !!context.node.data,
                dataKeys: context.node.data ? Object.keys(context.node.data) : null
            });

            // Validate that the node has required properties
            const nodeStoragePath = getNodeStoragePath(context.node);
            if (!context.node.id || !nodeStoragePath) {
                logger.error('single-player-page', '❌ Node missing required properties', {
                    nodeId: context.node.id,
                    hasStoragePath: !!nodeStoragePath,
                    node: context.node
                });
                setLoadingState({ 
                    status: 'error', 
                    error: 'Node is missing required information'
                });
                return;
            }

            try {
                setLoadingState({ status: 'loading', error: '' });
                
                // Center the node
                const nodeData = await loadNodeData(context.node);
                await NodeCanvasService.centerCurrentNode(editorRef.current, context.node, nodeData);
                
                setIsInitialLoad(false);
                setLoadingState({ status: 'ready', error: '' });
            } catch (error) {
                logger.error('single-player-page', '❌ Failed to place initial node', error);
                setLoadingState({ 
                    status: 'error', 
                    error: error instanceof Error ? error.message : 'Failed to place initial node'
                });
            }
        };

        placeInitialNode();
    }, [context.node, store, isInitialLoad]);

    // Handle navigation changes
    useEffect(() => {
        const handleNodeChange = async () => {
            if (!context.node?.id || !editorRef.current || !snapshotServiceRef.current || !store) {
                return;
            }

            // We can safely assert these types because we've checked for null above
            const editor = editorRef.current as Editor;
            const snapshotService = snapshotServiceRef.current;
            const currentNode = context.node;

            try {
                setLoadingState({ status: 'loading', error: '' });
                logger.debug('single-player-page', '🔄 Loading node data', {
                    nodeId: currentNode.id,
                    node_storage_path: currentNode.node_storage_path,
                    isInitialLoad
                });

                // Get the previous node from navigation history
                const previousNode = context.history.currentIndex > 0 
                    ? context.history.nodes[context.history.currentIndex - 1] 
                    : null;

                // Handle navigation in snapshot service
                await snapshotService.handleNavigationStart(previousNode, currentNode);

                // Center the node on canvas
                const nodeData = await loadNodeData(currentNode);
                await NodeCanvasService.centerCurrentNode(editor, currentNode, nodeData);

                setLoadingState({ status: 'ready', error: '' });
            } catch (error) {
                logger.error('single-player-page', '❌ Failed to load node data', error);
                setLoadingState({ 
                    status: 'error', 
                    error: error instanceof Error ? error.message : 'Failed to load node data'
                });
            }
        };

        handleNodeChange();
    }, [context.node, context.history, store, isInitialLoad]);

    // Initialize preferences when user is available
    useEffect(() => {
        if (user?.id && !tldrawPreferences) {
            logger.debug('single-player-page', '🔄 Initializing preferences for user', { userId: user.id });
            initializePreferences(user.id);
        }
    }, [user?.id, tldrawPreferences, initializePreferences]);

    // Redirect if no user or incorrect role
    useEffect(() => {
        if (!user || !['admin', 'email_teacher', 'school_admin', 'teacher'].includes(user.user_type || '')) {
            logger.info('single-player-page', '🚪 Redirecting to home - no user or incorrect role', {
                hasUser: !!user,
                userType: user?.user_type
            });
            routerNavigate('/', { replace: true });
        }
    }, [user, routerNavigate]);

    // Handle presentation mode
    useEffect(() => {
        if (presentationMode && editorRef.current) {
            logger.info('presentation', '🔄 Presentation mode changed', { 
                presentationMode,
                editorExists: !!editorRef.current
            });

            const editor = editorRef.current;
            const presentationService = new PresentationService(editor);
            const cleanup = presentationService.startPresentationMode();

            return () => {
                logger.info('presentation', '🧹 Cleaning up presentation mode');
                presentationService.stopPresentationMode();
                cleanup();
            };
        }
    }, [presentationMode]);

    // Handle shared content
    useEffect(() => {
        const handleSharedContent = async () => {
            if (!editorRef.current || !location.state) {
              return;
            }

            const editor = editorRef.current;
            const { sharedFile, sharedContent } = location.state as {
                sharedFile?: File;
                sharedContent?: {
                    title?: string;
                    text?: string;
                    url?: string;
                };
            };

            if (sharedFile) {
                logger.info('single-player-page', '📤 Processing shared file', { 
                    name: sharedFile.name,
                    type: sharedFile.type
                });

                try {
                    // Handle different file types
                    if (sharedFile.type.startsWith('image/')) {
                        const imageUrl = URL.createObjectURL(sharedFile);
                        await editor.createShape({
                            type: 'image',
                            props: {
                                url: imageUrl,
                                w: 320,
                                h: 240,
                                name: sharedFile.name
                            }
                        });
                        URL.revokeObjectURL(imageUrl);
                    } else if (sharedFile.type === 'application/pdf') {
                        // Handle PDF (you might want to implement PDF handling)
                        logger.info('single-player-page', '📄 PDF handling not implemented yet');
                    } else if (sharedFile.type === 'text/plain') {
                        const text = await sharedFile.text();
                        editor.createShape({
                            type: 'text',
                            props: { text }
                        });
                    }
                } catch (error) {
                    logger.error('single-player-page', '❌ Error processing shared file', { error });
                }
            }

            if (sharedContent) {
                logger.info('single-player-page', '📤 Processing shared content', { sharedContent });
                
                const { title, text, url } = sharedContent;
                let contentText = '';
                
                if (title) {
                  contentText += `${title}\n`;
                }
                if (text) {
                  contentText += `${text}\n`;
                }
                if (url) {
                  contentText += url;
                }

                if (contentText) {
                    editor.createShape({
                        type: 'text',
                        props: { text: contentText }
                    });
                }
            }
        };

        handleSharedContent();
    }, [location.state]);

    // Modify the render logic to use presentationMode
    const uiOverrides = getUiOverrides(presentationMode);
    const uiComponents = getUiComponents(presentationMode);

    // Show loading state if user context is still loading
    if (userLoading || !user) {
        return (
            <div style={{ 
                position: 'fixed',
                inset: 0,
                top: `${HEADER_HEIGHT}px`,
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                backgroundColor: 'var(--color-background)'
            }}>
                <CircularProgress />
            </div>
        );
    }

    return (
        <div style={{ 
            position: 'fixed',
            inset: 0,
            top: `${HEADER_HEIGHT}px`,
            display: 'flex',
            flexDirection: 'column',
            overflow: 'hidden'
        }}>
            {/* Loading overlay - show when loading or contexts not initialized */}
            {(loadingState.status === 'loading' || !store) && (
                <div style={{
                    position: 'absolute',
                    top: 0,
                    left: 0,
                    right: 0,
                    bottom: 0,
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    backgroundColor: 'rgba(255, 255, 255, 0.8)',
                    zIndex: 1000,
                }}>
                    <CircularProgress />
                </div>
            )}

            {/* Error snackbar */}
            <Snackbar 
                open={loadingState.status === 'error'} 
                autoHideDuration={6000}
                onClose={() => setLoadingState({ status: 'ready', error: '' })}
            >
                <Alert severity="error" onClose={() => setLoadingState({ status: 'ready', error: '' })}>
                    {loadingState.error}
                </Alert>
            </Snackbar>

            {store && <Tldraw
                user={tldrawUser}
                store={store}
                tools={singlePlayerTools}
                shapeUtils={allShapeUtils}
                bindingUtils={allBindingUtils}
                components={uiComponents}
                overrides={uiOverrides}
                embeds={singlePlayerEmbeds}
                assetUrls={customAssets}
                autoFocus={true}
                hideUi={false}
                inferDarkMode={false}
                acceptedImageMimeTypes={DEFAULT_SUPPORTED_IMAGE_TYPES}
                acceptedVideoMimeTypes={DEFAULT_SUPPORT_VIDEO_TYPES}
                maxImageDimension={Infinity}
                maxAssetSize={100 * 1024 * 1024}
                renderDebugMenuItems={() => []}
                onMount={(editor) => {
                    logger.info('single-player-page', '🎨 Starting Tldraw mount');
                    try {
                        if (!editor) {
                            logger.error('single-player-page', '❌ Editor is null in onMount');
                            return;
                        }
                        
                        editorRef.current = editor;
                        logger.debug('single-player-page', '✅ Editor ref set');
                        
                        // Update snapshot service with editor reference
                        if (snapshotServiceRef.current) {
                            snapshotServiceRef.current.setEditor(editor);
                        }
                        
                        setIsEditorReady(true);
                        logger.info('single-player-page', '✅ Tldraw mounted successfully', {
                            editorId: editor.store.id,
                            presentationMode,
                            isEditorReady: true
                        });
                    } catch (error) {
                        logger.error('single-player-page', '❌ Error in onMount', error);
                    }
                }}
            />}
        </div>
    );
}

// Helper function to safely extract node_storage_path from different node structures
const getNodeStoragePath = (node: NavigationNode): string | null => {
    // Try direct access first
    if (node.node_storage_path) {
        return node.node_storage_path;
    }
    
    // Try nested under data
    if (node.data?.node_storage_path) {
        return node.data.node_storage_path;
    }
    
    // Try other possible locations
    if (node.data?.storage_path && typeof node.data.storage_path === 'string') {
        return node.data.storage_path;
    }
    
    return null;
};

const loadNodeData = async (node: NavigationNode): Promise<NodeData> => {
    // Validate the node parameter
    if (!node) {
        throw new Error('Node parameter is required');
    }
    
    if (!node.id) {
        throw new Error('Node must have an ID');
    }
    
    const nodeStoragePath = getNodeStoragePath(node);
    if (!nodeStoragePath) {
        throw new Error(`Node ${node.id} is missing node_storage_path`);
    }
    
    logger.debug('single-player-page', '🔄 Loading node data', {
        nodeId: node.id,
        nodeType: node.type,
        nodeLabel: node.label,
        nodeStoragePath: nodeStoragePath
    });

    try {
        // 1. Always fetch fresh data
        // Create a temporary node object with the correct structure for the service
        const normalizedNode = {
            ...node,
            node_storage_path: nodeStoragePath
        };
        
        const dbName = UserNeoDBService.getNodeDatabaseName(normalizedNode);
        const fetchedData = await UserNeoDBService.fetchNodeData(node.id, dbName);
        
        if (!fetchedData?.node_data) {
            throw new Error('Failed to fetch node data');
        }

        // 2. Process the data into the correct shape
        const theme = getThemeFromLabel(node.type);
        return {
            ...fetchedData.node_data,
            title: String(fetchedData.node_data.title || node.label || ''),
            w: 500,
            h: 350,
            state: {
                parentId: null,
                isPageChild: true,
                hasChildren: null,
                bindings: null
            },
            headerColor: theme.headerColor,
            backgroundColor: theme.backgroundColor,
            isLocked: false,
            __primarylabel__: node.type,
            uuid_string: node.id,
            node_storage_path: nodeStoragePath
        };
    } catch (error) {
        logger.error('single-player-page', '❌ Error in loadNodeData', {
            nodeId: node.id,
            nodeType: node.type,
            error: error instanceof Error ? error.message : String(error)
        });
        throw error;
    }
};
