import { useEffect, useState, useMemo, useRef } from 'react';
import { useShallow } from 'zustand/react/shallow';
import { AppNodeType, NodeType, NodeStatus } from '../types/node';
import { useProjectStore } from '@/lib/store/project';
import { useCanvasContext } from '../CanvasContext';
import { loadCanvasStateFromStorage } from '../services/storage';
import { useReactFlow, Edge } from '@xyflow/react';
import { useCanvasStore } from '@/lib/store/canvasStore';
import { 
    useProjectCanvases, 
    useAssetCanvas, 
    useStoryboardCanvas, 
    useCreateGeneralCanvas 
} from '@/lib/hooks/useCanvasMetadata';
import { errorRecovery } from '@/lib/utils/errorRecovery';
import { logger } from '@/lib/utils/logger';

const log = logger.namespace('CanvasInit');

interface UseCanvasInitializationProps {
    setNodes: React.Dispatch<React.SetStateAction<AppNodeType[]>>;
    setEdges: React.Dispatch<React.SetStateAction<Edge[]>>;
    getStorageKey: (id: string | null, type: string) => string;
}

export const useCanvasInitialization = ({
    setNodes,
    setEdges,
    getStorageKey
}: UseCanvasInitializationProps) => {
    const { assets, storyboards, projectId } = useProjectStore(
        useShallow((s) => ({ assets: s.assets, storyboards: s.storyboards, projectId: s.id }))
    );
    const { initialAssetId, initialStoryboardId } = useCanvasContext();
    const { setCenter } = useReactFlow();
    const setGenerationHistory = useCanvasStore(state => state.setGenerationHistory);

    // Query canvas metadata using new hooks
    const { data: generalCanvases, isLoading: isLoadingGeneral } = useProjectCanvases(
        projectId || '', 
        'general'
    );
    const { data: assetCanvas, isLoading: isLoadingAsset } = useAssetCanvas(
        initialAssetId || null
    );
    const { data: storyboardCanvas, isLoading: isLoadingStoryboard } = useStoryboardCanvas(
        initialStoryboardId || null
    );
    const { mutate: createGeneralCanvas } = useCreateGeneralCanvas();
    const createGeneralCanvasRef = useRef(createGeneralCanvas);
    createGeneralCanvasRef.current = createGeneralCanvas;

    // Refs for init effect: read latest in init without re-running when workspace/canvas list updates (avoids max update depth on new project)
    const assetsRef = useRef(assets);
    const storyboardsRef = useRef(storyboards);
    const generalCanvasesRef = useRef(generalCanvases);
    const assetCanvasRef = useRef(assetCanvas);
    const storyboardCanvasRef = useRef(storyboardCanvas);
    assetsRef.current = assets;
    storyboardsRef.current = storyboards;
    generalCanvasesRef.current = generalCanvases;
    assetCanvasRef.current = assetCanvas;
    storyboardCanvasRef.current = storyboardCanvas;

    // Determine initial canvas - prioritize general canvas
    // Use useMemo to avoid recreating on every render
    const initialCanvas = useMemo(() => {
        log.log('Computing initial canvas:', {
            initialAssetId,
            initialStoryboardId,
            generalCanvasesCount: generalCanvases?.length || 0,
            firstCanvasId: generalCanvases?.[0]?.id,
            projectId,
            assetCanvas: assetCanvas?.id,
            storyboardCanvas: storyboardCanvas?.id
        });
        
        // If explicitly passed initial IDs, use them
        if (initialAssetId && assetCanvas) {
            return { id: assetCanvas.id, type: 'asset' as const, metadata: assetCanvas };
        }
        if (initialStoryboardId && storyboardCanvas) {
            return { id: storyboardCanvas.id, type: 'storyboard' as const, metadata: storyboardCanvas };
        }
        
        // Otherwise, use first general canvas
        if (generalCanvases && generalCanvases.length && generalCanvases.length > 0) {
            log.log('Using first general canvas:', generalCanvases[0].id);
            return { id: generalCanvases[0].id, type: 'main' as const, metadata: generalCanvases[0] };
        }
        
        // If no general canvas exists, return null (will create one in useEffect)
        log.log('No general canvas found, will create default');
        return { id: null, type: 'main' as const, metadata: null };
    }, [initialAssetId, initialStoryboardId, generalCanvases, projectId, assetCanvas, storyboardCanvas]);

    // Active Canvas State
    const [activeCanvasId, setActiveCanvasId] = useState<string | null>(initialCanvas.id);
    const [activeCanvasType, setActiveCanvasType] = useState<'main' | 'asset' | 'storyboard'>(initialCanvas.type);
    const [isCanvasLoaded, setIsCanvasLoaded] = useState(false);

    // 打开项目时若无通用画布则自动创建一个（每个 projectId 只尝试一次，避免重复创建）
    const hasTriedCreateForProjectRef = useRef<string | null>(null);

    useEffect(() => {
        if (!projectId) {
            hasTriedCreateForProjectRef.current = null;
            return;
        }
        // 仅当接口已返回（非 loading）且明确返回空列表时才创建，避免 query 未就绪时误判
        if (isLoadingGeneral) return;
        if (generalCanvases === undefined || generalCanvases === null) return;
        const listEmpty = generalCanvases.length === 0;
        const alreadyTried = hasTriedCreateForProjectRef.current === projectId;
        if (!listEmpty || alreadyTried) return;

        hasTriedCreateForProjectRef.current = projectId;
        log.log('Creating default general canvas for project:', projectId);
        const mutate = createGeneralCanvasRef.current;
        mutate(
            {
                projectId,
                data: { name: '通用画布' },
            },
            {
                onSuccess: (canvas: { id: string }) => {
                    log.log('Default canvas created:', canvas.id);
                    // 推迟到下一 tick 再 setState，避免与 React Query 的乐观更新在同一 commit 中触发连锁渲染
                    const id = canvas.id;
                    queueMicrotask(() => {
                        setActiveCanvasId(id);
                        setActiveCanvasType('main');
                    });
                },
                onError: (error: Error) => {
                    log.error('Failed to create default canvas:', error);
                    hasTriedCreateForProjectRef.current = null;
                },
            }
        );
    }, [projectId, generalCanvases, isLoadingGeneral]);

    // 切换项目时清空画布并标记未加载，避免仍显示上一项目的画布
    useEffect(() => {
        setIsCanvasLoaded(false);
        setNodes([]);
        setEdges([]);
    }, [projectId, setNodes, setEdges]);

    // Initialization Logic (deps exclude assets/storyboards/generalCanvases/assetCanvas/storyboardCanvas to avoid re-runs on workspace/canvas list updates → max update depth on new project)
    useEffect(() => {
        const init = async () => {
            if (isCanvasLoaded) return;

            const key = getStorageKey(activeCanvasId, activeCanvasType);

            const gCanvases = generalCanvasesRef.current;
            const aCanvas = assetCanvasRef.current;
            const sCanvas = storyboardCanvasRef.current;

            // Determine which metadata to use based on canvas type (read from refs)
            let canvasMetadata = null;
            if (activeCanvasType === 'asset' && aCanvas) {
                canvasMetadata = aCanvas;
            } else if (activeCanvasType === 'storyboard' && sCanvas) {
                canvasMetadata = sCanvas;
            } else if (activeCanvasType === 'main' && gCanvases && activeCanvasId && typeof gCanvases.find === 'function') {
                canvasMetadata = gCanvases.find((c: { id: string }) => c.id === activeCanvasId);
            }

            try {
                // Check for recovery data first
                let recoveredState = null;
                if (activeCanvasId && errorRecovery.needsRecovery(activeCanvasId)) {
                    log.log('Recovery data found for canvas:', activeCanvasId);
                    const recoveryInfo = errorRecovery.getRecoveryInfo();
                    
                    if (recoveryInfo) {
                        log.log('Recovery info:', {
                            canvasId: recoveryInfo.canvasId,
                            errorMessage: recoveryInfo.errorMessage,
                            age: errorRecovery.getFormattedRecoveryAge(),
                            metadata: recoveryInfo.metadata
                        });

                        // Attempt to recover the canvas state
                        recoveredState = await errorRecovery.recoverCanvas(activeCanvasId);
                        
                        if (recoveredState) {
                            log.log('Successfully recovered canvas state');
                            
                            // Apply recovered state
                            if (recoveredState.nodes && recoveredState.nodes.length > 0) {
                                setNodes(recoveredState.nodes);
                                setEdges(recoveredState.edges || []);
                            }
                            if (recoveredState.history) {
                                setGenerationHistory(recoveredState.history);
                            }

                            // Clear recovery data after successful recovery
                            errorRecovery.clearRecoveryData();
                            
                            // Mark canvas as loaded and return early
                            setIsCanvasLoaded(true);
                            return;
                        } else {
                            log.warn('Failed to recover canvas state, falling back to normal load');
                        }
                    }
                }

                // Try load from Storage with metadata for caching
                const savedData = await loadCanvasStateFromStorage<{ nodes: AppNodeType[], edges: Edge[], history?: any[] }>(
                    key, 
                    projectId || undefined,
                    canvasMetadata || undefined
                );

                if (savedData) {
                    if (savedData.nodes && savedData.nodes.length > 0) {
                        setNodes(savedData.nodes);
                        setEdges(savedData.edges || []);
                    }
                    if (savedData.history) {
                        setGenerationHistory(savedData.history);
                    }
                }

                if (!savedData || !savedData.nodes || savedData.nodes.length === 0) {
                    // Initialize New Canvas Context (read from refs to avoid effect re-run when workspace loads)
                    const currentAssets = assetsRef.current;
                    const currentStoryboards = storyboardsRef.current;
                    let newNodes: AppNodeType[] = [];

                    if (activeCanvasType === 'asset' && activeCanvasId) {
                        const relatedAssetId = aCanvas?.relatedEntityId || initialAssetId;
                        const asset = currentAssets.find(a => a.id === relatedAssetId);
                        if (asset) {
                            const imageUrl = asset.imageUrl || (asset.imageUrls && asset.imageUrls[0]);
                            const videoUrl = (asset.videoUrls && asset.videoUrls[0]);

                            const newNode: AppNodeType = {
                                id: `node-${Date.now()}`,
                                type: 'appNode',
                                position: { x: window.innerWidth / 2 - 210, y: window.innerHeight / 2 - 200 },
                                data: {
                                    title: asset.name || 'Input Asset',
                                    type: NodeType.INFO_DISPLAY,
                                    status: NodeStatus.SUCCESS,
                                    assetInfo: asset,
                                    image: imageUrl,
                                    videoUri: videoUrl,
                                    prompt: asset.desc || '',
                                }
                            };
                            newNodes = [newNode];
                        }
                    } else if (activeCanvasType === 'storyboard' && activeCanvasId) {
                        const relatedStoryboardId = sCanvas?.relatedEntityId || initialStoryboardId;
                        const storyboard = currentStoryboards.find(s => s.id === relatedStoryboardId);
                        if (storyboard) {
                            const imageUrl = storyboard.imageUrls?.[0];
                            const videoUrl = storyboard.videoUrls?.[0];

                            const relatedScene = storyboard.sceneId ? currentAssets.find(a => a.id === storyboard.sceneId) : undefined;
                            const relatedCharacters = storyboard.characterIds?.map(id => currentAssets.find(a => a.id === id)).filter(Boolean) || [];
                            const relatedProps = storyboard.propIds?.map(id => currentAssets.find(a => a.id === id)).filter(Boolean) || [];

                            const newNode: AppNodeType = {
                                id: `node-${Date.now()}`,
                                type: 'appNode',
                                position: { x: window.innerWidth / 2 - 210, y: window.innerHeight / 2 - 200 },
                                data: {
                                    title: storyboard.shot || 'Storyboard Info',
                                    type: NodeType.INFO_DISPLAY,
                                    status: NodeStatus.SUCCESS,
                                    assetInfo: {
                                        ...storyboard,
                                        type: 'storyboard',
                                        resolvedScene: relatedScene,
                                        resolvedCharacters: relatedCharacters,
                                        resolvedProps: relatedProps
                                    },
                                    image: imageUrl,
                                    videoUri: videoUrl,
                                    prompt: storyboard.desc || '',
                                }
                            };
                            newNodes = [newNode];
                        }
                    }

                    setNodes(newNodes);
                    setEdges([]);

                    // Only center if we created new nodes
                    if (newNodes.length > 0) {
                        setTimeout(() => setCenter(window.innerWidth / 2, window.innerHeight / 2, { zoom: 0.75, duration: 800 }), 100);
                    }
                }
            } catch (e) {
                log.error('Failed to load canvas state', e);
            } finally {
                setIsCanvasLoaded(true);
            }
        };

        init();
    }, [
        activeCanvasId,
        activeCanvasType,
        isCanvasLoaded,
        setNodes,
        setEdges,
        setCenter,
        getStorageKey,
        projectId,
        setGenerationHistory,
        initialAssetId,
        initialStoryboardId,
    ]);

    // Determine current canvas metadata
    const currentCanvasMetadata = useMemo(() => {
        if (activeCanvasType === 'asset' && assetCanvas) {
            return assetCanvas;
        } else if (activeCanvasType === 'storyboard' && storyboardCanvas) {
            return storyboardCanvas;
        } else if (activeCanvasType === 'main' && generalCanvases && activeCanvasId && typeof generalCanvases.find === 'function') {
            return generalCanvases.find((c: { id: string }) => c.id === activeCanvasId);
        }
        return null;
    }, [activeCanvasType, activeCanvasId, assetCanvas, storyboardCanvas, generalCanvases]);

    return {
        activeCanvasId,
        setActiveCanvasId,
        activeCanvasType,
        setActiveCanvasType,
        isCanvasLoaded,
        setIsCanvasLoaded,
        currentCanvasMetadata
    };
};
