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,
    createTLStore,
} from '@tldraw/tldraw';
import { useTLDraw } from '../../contexts/TLDrawContext';
import { useAuth } from '../../contexts/AuthContext';
import { useUser } from '../../contexts/UserContext';
// Tldraw services
import { localStoreService } from '../../services/tldraw/localStoreService';
import { PresentationService } from '../../services/tldraw/presentationService';
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 { ErrorBoundary } from '../../components/ErrorBoundary';

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

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


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

    // State
    const [loadingState, setLoadingState] = useState<LoadingState>({
        status: 'ready',
        error: ''
    });
    const storeRef = useRef<TLStore | null>(null);
    const [storeReady, setStoreReady] = useState(false);

    // 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
    });

    const [canvasPhase, setCanvasPhase] = useState<
        'idle' | 'store-init' | 'snapshot-loading' | 'ready' | 'error'
    >('idle');

    // Effect 1: Create the store ONCE per user session. Never recreate on node changes.
    // Disposing the store while Tldraw is subscribed causes currentPageId crashes; keeping
    // the store alive for the component lifetime avoids all disposal race conditions.
    useEffect(() => {
        if (!user) return;

        setCanvasPhase('store-init');
        const store = createTLStore({
            schema: customSchema,
            shapeUtils: allShapeUtils,
            bindingUtils: allBindingUtils,
        });
        // Initialize default tldraw records (TLINSTANCE, page, cameras) before mount
        (store as unknown as { ensureStoreIsUsable(): void }).ensureStoreIsUsable();

        const snapSvc = new NavigationSnapshotService(store, undefined);
        if (accessToken) snapSvc.setAccessToken(accessToken);
        snapshotServiceRef.current = snapSvc;

        let debounce: ReturnType<typeof setTimeout> | null = null;
        const unsubscribe = store.listen(() => {
            if (!snapshotServiceRef.current?.getCurrentNodePath()) return;
            if (debounce) clearTimeout(debounce);
            debounce = setTimeout(async () => {
                await snapshotServiceRef.current?.forceSaveCurrentNode().catch(() => {});
            }, 2000);
        });

        storeRef.current = store;
        setStoreReady(true);
        setCanvasPhase('ready');

        return () => {
            unsubscribe?.();
            snapshotServiceRef.current?.forceSaveCurrentNode().catch(() => {});
            snapshotServiceRef.current?.clearCurrentNode();
            snapshotServiceRef.current = null;
            setStoreReady(false);
            setCanvasPhase('idle');
            store.dispose();
            storeRef.current = null;
        };
    }, [user?.id]);  // Only recreate store if user changes, NOT on every node navigation

    // Effect 2: Load/reload snapshot when context.node changes. Store stays alive.
    useEffect(() => {
        if (!user || !storeRef.current) return;

        const store = storeRef.current;
        let cancelled = false;

        const loadNodeSnapshot = async () => {
            if (!context.node?.node_storage_path) {
                // No node — clear to blank canvas using ensureStoreIsUsable to restore defaults
                (store as unknown as { ensureStoreIsUsable(): void }).ensureStoreIsUsable();
                snapshotServiceRef.current?.clearCurrentNode();
                setCanvasPhase('ready');
                return;
            }

            setCanvasPhase('snapshot-loading');
            try {
                await NavigationSnapshotService.loadNodeSnapshotFromDatabase(
                    context.node.node_storage_path,
                    accessToken || '',
                    store,
                    setLoadingState,
                    undefined,
                    editorRef.current || undefined
                );
                if (!cancelled) {
                    // Repair store in case snapshot overwrote TLINSTANCE
                    (store as unknown as { ensureStoreIsUsable(): void }).ensureStoreIsUsable();
                    snapshotServiceRef.current?.setCurrentNodePath(context.node.node_storage_path);
                    setCanvasPhase('ready');
                }
            } catch (e) {
                if (!cancelled) setCanvasPhase('ready'); // show blank canvas on error
            }
        };

        loadNodeSnapshot();
        return () => { cancelled = true; };
    }, [context.node?.id, storeReady]);  // re-run when node changes OR after store becomes ready

    // Handle navigation changes — save previous snapshot, load next one.
    // No automatic node shape placement: the canvas shows only persisted state.

    // Inject auth and trigger initial context when token is ready
    useEffect(() => {
        if (user?.id && accessToken) {
            setAuthInfo(accessToken, user.id);
            if (!context.node) {
                switchContext({ main: 'profile', base: 'profile' }, null, null);
            }
        }
    }, [user?.id, accessToken]);

    // 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`,
        }}>
            {/* Loading overlay - show when loading or contexts not initialized */}
            {(loadingState.status === 'loading' || !storeReady) && (
                <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>

            <ErrorBoundary fallback={
                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', gap: '1rem', padding: '2rem' }}>
                    <p style={{ fontSize: '1.1rem' }}>Canvas failed to load.</p>
                    <button onClick={() => window.location.reload()} style={{ padding: '0.5rem 1.25rem', cursor: 'pointer' }}>Reload</button>
                </div>
            }>
            {storeReady && storeRef.current && <Tldraw
                user={tldrawUser}
                store={storeRef.current}
                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);
                            if (accessToken) snapshotServiceRef.current.setAccessToken(accessToken);
                        }

                        logger.info('single-player-page', '✅ Tldraw mounted successfully', {
                            editorId: editor.store.id,
                            presentationMode,
                        });
                    } catch (error) {
                        logger.error('single-player-page', '❌ Error in onMount', error);
                    }
                }}
            />}
            </ErrorBoundary>
        </div>
    );
}

