import { useCallback } from 'react';
import { useReactFlow, Edge, addEdge } from '@xyflow/react';
import { NodeType, AppNodeType, NodeStatus, InputAsset } from '../types/node';
import { generateImage, generateVideo, generateAudio, generateMusic, generateLyrics } from '../services/canvasService';
import { useAssetSaver } from '../hooks/useAssetSaver';
import { useModelStore } from '@lib/store/modelStore';
import { useCanvasStore } from '@lib/store/canvasStore';
import { getNodeNameCN } from '../utils';

interface UseCanvasInteractionProps {
    saveContext: { assetId: string | null; storyboardId: string | null };
    setNodes: React.Dispatch<React.SetStateAction<AppNodeType[]>>;
    setEdges: React.Dispatch<React.SetStateAction<Edge[]>>;
    saveAsset: ReturnType<typeof useAssetSaver>['saveAsset'];
}

export const useCanvasInteraction = ({
    saveContext,
    setNodes,
    setEdges,
    saveAsset
}: UseCanvasInteractionProps) => {
    const { screenToFlowPosition, getNodes } = useReactFlow();
    const { getDefaultModelId, lyricsModels, musicModels } = useModelStore();
    const addGenerationHistoryItem = useCanvasStore(state => state.addGenerationHistoryItem);

    const getImageModelDefault = useCallback(() => {
        return getDefaultModelId('image');
    }, [getDefaultModelId]);

    const getVideoModelDefault = useCallback(() => {
        return getDefaultModelId('video');
    }, [getDefaultModelId]);

    const getAudioModelDefault = useCallback(() => {
        return getDefaultModelId('audio');
    }, [getDefaultModelId]);

    const getMusicModelDefault = useCallback(() => {
        return getDefaultModelId('music');
    }, [getDefaultModelId]);

    const getLyricsModelDefault = useCallback(() => {
        return getDefaultModelId('lyrics');
    }, [getDefaultModelId]);

    const getLLMModelDefault = useCallback(() => {
        return getDefaultModelId('llm');
    }, [getDefaultModelId]);

    const handleAddNode = useCallback((type: NodeType, position?: { x: number; y: number }, data?: Partial<any>) => {
        // takeSnapshot(nodes, edges); // Snapshot handled in parent or via callback if needed
        const defaultPosition = screenToFlowPosition({ 
            x: window.innerWidth / 2 - 150, 
            y: window.innerHeight / 2 - 100 
        });
        
        let defaultModel = '';
        if (type === NodeType.IMAGE_GENERATOR || type === NodeType.IMAGE_EDITOR) {
            defaultModel = getImageModelDefault();
        } else if (type === NodeType.VIDEO_GENERATOR) {
            defaultModel = getVideoModelDefault();
        } else if (type === NodeType.LYRICS_GENERATOR) {
            defaultModel = getLyricsModelDefault();
        } else if (type === NodeType.AUDIO_GENERATOR) {
            defaultModel = data?.generationType === 'music' ? getMusicModelDefault() : getAudioModelDefault();
        } else if (type === NodeType.PROMPT_GENERATOR || type === NodeType.VIDEO_ANALYZER) {
            defaultModel = getLLMModelDefault();
        }
        
        // Get current nodes to find max zIndex
        const currentNodes = getNodes();
        const maxZIndex = currentNodes.reduce((max, node) => {
            return Math.max(max, node.zIndex ?? 0);
        }, 0);
        
        const newNode: AppNodeType = {
            id: `${type}-${Date.now()}`,
            type: 'appNode',
            position: position || defaultPosition,
            zIndex: maxZIndex + 1, // Set new node to top layer
            data: { 
                title: data?.title || getNodeNameCN(type), 
                type: type, 
                status: 'IDLE',
                model: defaultModel,
                ...data
            }
        };
        setNodes((nds) => nds.concat(newNode));
    }, [screenToFlowPosition, setNodes, getNodes, getImageModelDefault, getVideoModelDefault, getAudioModelDefault, getMusicModelDefault, getLyricsModelDefault, getLLMModelDefault]);

    const handleCreateAndConnect = useCallback((
        type: NodeType, 
        sourceNodeId: string | undefined,
        nodes: AppNodeType[], 
        edges: Edge[], 
        takeSnapshot?: (nodes: AppNodeType[], edges: Edge[]) => void,
        data?: Partial<any>
    ) => {
        if (!sourceNodeId) return;
        const sourceNode = nodes.find(n => n.id === sourceNodeId);
        if (!sourceNode) return;

        if (takeSnapshot) {
            takeSnapshot(nodes, edges);
        }

        const newNodeId = `${type}-${Date.now()}`;
        // Calculate position: right of source node
        const offset = (sourceNode.width || 420) + 100;
        
        let defaultModel = '';
        if (type === NodeType.IMAGE_GENERATOR || type === NodeType.IMAGE_EDITOR) {
            defaultModel = getImageModelDefault();
        } else if (type === NodeType.VIDEO_GENERATOR) {
            defaultModel = getVideoModelDefault();
        } else if (type === NodeType.LYRICS_GENERATOR) {
            defaultModel = getLyricsModelDefault();
        } else if (type === NodeType.AUDIO_GENERATOR) {
            defaultModel = data?.generationType === 'music' ? getMusicModelDefault() : getAudioModelDefault();
        } else if (type === NodeType.PROMPT_GENERATOR || type === NodeType.VIDEO_ANALYZER) {
            defaultModel = getLLMModelDefault();
        }
        
        // Find max zIndex
        const maxZIndex = nodes.reduce((max, node) => {
            return Math.max(max, node.zIndex ?? 0);
        }, 0);
        
        const newNode: AppNodeType = {
            id: newNodeId,
            type: 'appNode',
            position: { 
                x: sourceNode.position.x + offset, 
                y: sourceNode.position.y 
            },
            zIndex: maxZIndex + 1, // Set new node to top layer
            data: { 
                title: data?.title || getNodeNameCN(type), 
                type: type, 
                status: 'IDLE',
                model: defaultModel,
                ...data,
            }
        };

        const newEdge: Edge = {
            id: `e-${sourceNodeId}-${newNodeId}`,
            source: sourceNodeId,
            target: newNodeId,
            type: 'gradient',
        };

        setNodes((nds) => nds.concat(newNode));
        setEdges((eds) => addEdge(newEdge, eds));
    }, [setNodes, setEdges, getImageModelDefault, getVideoModelDefault, getAudioModelDefault, getMusicModelDefault, getLyricsModelDefault, getLLMModelDefault]);

    const handleSketchResult = useCallback((type: 'image' | 'video', result: string, prompt: string) => {
        // Determine context
        let generationContext = saveContext;
        if (!generationContext.assetId && !generationContext.storyboardId) {
            const currentNodes = getNodes();
            const selectedNodes = currentNodes.filter(n => n.selected && n.type === 'appNode');
            if (selectedNodes.length === 1) {
                const selectedNode = selectedNodes[0];
                if (selectedNode.type === 'appNode') {
                     const assetInfo = selectedNode.data.assetInfo as any;
                     if (assetInfo && assetInfo.id) {
                         if (assetInfo.type === 'storyboard') {
                             generationContext = { assetId: null, storyboardId: assetInfo.id };
                         } else {
                             generationContext = { assetId: assetInfo.id, storyboardId: null };
                         }
                     }
                }
            }
        }

        const centerX = window.innerWidth / 2 - 150;
        const centerY = window.innerHeight / 2 - 100;
        const pos = screenToFlowPosition({ x: centerX, y: centerY });

        if (type === 'image') {
            handleAddNode(NodeType.IMAGE_GENERATOR, pos, { image: result, prompt, status: NodeStatus.SUCCESS });
        } else {
            handleAddNode(NodeType.VIDEO_GENERATOR, pos, { videoUri: result, prompt, status: NodeStatus.SUCCESS });
        }

        addGenerationHistoryItem({
            id: `gen-${Date.now()}`,
            type: type,
            src: result,
            title: prompt || 'Sketch Output',
            timestamp: Date.now(),
            context: generationContext
        });
    }, [handleAddNode, screenToFlowPosition, saveContext, getNodes, addGenerationHistoryItem]);

    const handleInteractionGenerate = useCallback(async (data: { type: 'video' | 'image' | 'digital_human' | 'text' | 'audio' | 'music', prompt: string, settings: any, inputAssets?: InputAsset[] }) => {
        const centerX = window.innerWidth / 2 - 150; 
        const centerY = window.innerHeight / 2 - 100;

        let generationContext = saveContext;
        if (!generationContext.assetId && !generationContext.storyboardId) {
            const currentNodes = getNodes();
            const selectedNodes = currentNodes.filter(n => n.selected && n.type === 'appNode');
            if (selectedNodes.length === 1) {
                const selectedNode = selectedNodes[0];
                if (selectedNode.type === 'appNode') {
                     const assetInfo = selectedNode.data.assetInfo as any;
                     if (assetInfo && assetInfo.id) {
                         if (assetInfo.type === 'storyboard') {
                             generationContext = { assetId: null, storyboardId: assetInfo.id };
                         } else {
                             generationContext = { assetId: assetInfo.id, storyboardId: null };
                         }
                     }
                }
            }
        }

        const { type, prompt, settings, inputAssets = [] } = data;
        
        if (type === 'text') return; // Handled internally by InteractionInput

        const selectedMusicTarget: 'lyrics' | 'music' = settings.musicTarget === 'lyrics' ? 'lyrics' : 'music';
        const shouldGenerateLyricsRaw = settings.musicGenerateLyrics ?? (selectedMusicTarget === 'lyrics');
        const shouldGenerateMusicRaw = settings.musicGenerateMusic ?? (selectedMusicTarget === 'music');
        const shouldGenerateLyrics = shouldGenerateLyricsRaw || !shouldGenerateMusicRaw;
        const shouldGenerateMusic = shouldGenerateMusicRaw || !shouldGenerateLyricsRaw;
        const resolvedMusicModel = settings.musicModel || getMusicModelDefault();
        const resolvedLyricsModel = settings.lyricsModel || getLyricsModelDefault();
        const model = settings.model || (
            type === 'image' ? getImageModelDefault() : 
            type === 'video' ? getVideoModelDefault() :
            type === 'audio' ? getAudioModelDefault() :
            type === 'music' ? (shouldGenerateMusic ? resolvedMusicModel : resolvedLyricsModel) : ''
        );
        const count = settings.count || 1;

        const placeholderIds: string[] = [];
        const lyricsPlaceholderIds: string[] = [];
        const musicPlaceholderIds: string[] = [];
        const placeholders: AppNodeType[] = [];
        const newEdges: Edge[] = [];

        // Prepare input assets
        const inputImages = inputAssets
            .filter(a => a.type === 'image')
            .map(a => a.src);
            
        const inputVideos = inputAssets
            .filter(a => a.type === 'video')
            .map(a => a.src);

        // For image/video: single node with multiple images/videos
        // For audio/music: multiple nodes (each generates one)
        const isSingleNodeMultiMedia = type === 'image' || type === 'video';

        if (isSingleNodeMultiMedia) {
            // Single node mode for image/video with count
            const nodePos = screenToFlowPosition({ x: centerX, y: centerY });
            const tempId = `gen-temp-${Date.now()}`;
            placeholderIds.push(tempId);

            let nodeTitle = type === 'image' ? `图片生成 (${count}张)` : `视频生成 (${count}个)`;
            let nodeType = type === 'image' ? NodeType.IMAGE_GENERATOR : NodeType.VIDEO_GENERATOR;

            placeholders.push({
                id: tempId,
                type: 'appNode',
                position: nodePos,
                data: {
                    title: nodeTitle,
                    type: nodeType,
                    status: 'WORKING',
                    model,
                    prompt,
                    aspectRatio: settings.aspectRatio,
                    voice: settings.voice,
                    styleId: settings.styleId,
                    resolution: settings.resolution,
                    imageCount: type === 'image' ? count : undefined,
                    videoCount: type === 'video' ? count : undefined,
                    shotType: settings.shotType,
                    enableAudio: settings.enableAudio,
                    cameraControl: settings.cameraControl,
                    inputAssets: inputAssets
                }
            });

            // Create edges from input assets to the new node
            inputAssets.forEach(asset => {
                if (asset.id) {
                    newEdges.push({
                        id: `e-${asset.id}-${tempId}`,
                        source: asset.id,
                        target: tempId,
                        type: 'gradient',
                        animated: true
                    });
                }
            });
        } else {
            // Multi-node mode for audio/music (each node generates one)
            for (let i = 0; i < count; i++) {
                 const offsetX = (i % 2) * 350;
                 const offsetY = Math.floor(i / 2) * 350;
                 const nodePos = screenToFlowPosition({
                     x: centerX + offsetX,
                     y: centerY + offsetY
                 });

                 if (type === 'music' && shouldGenerateLyrics && shouldGenerateMusic) {
                     const lyricsTempId = `gen-lyrics-temp-${Date.now()}-${i}`;
                     const musicTempId = `gen-music-temp-${Date.now()}-${i}`;
                     placeholderIds.push(lyricsTempId, musicTempId);
                     lyricsPlaceholderIds.push(lyricsTempId);
                     musicPlaceholderIds.push(musicTempId);

                     placeholders.push({
                         id: lyricsTempId,
                         type: 'appNode',
                         position: nodePos,
                         data: {
                             title: '歌词生成',
                             type: NodeType.LYRICS_GENERATOR,
                             status: 'WORKING',
                             model: resolvedLyricsModel,
                             prompt,
                             inputAssets
                         }
                     });

                     placeholders.push({
                         id: musicTempId,
                         type: 'appNode',
                         position: { x: nodePos.x + 460, y: nodePos.y },
                         data: {
                             title: '音乐生成',
                             type: NodeType.AUDIO_GENERATOR,
                             status: 'WORKING',
                             model: resolvedMusicModel,
                             prompt,
                             generationType: 'music',
                             inputAssets
                         }
                     });

                     newEdges.push({
                         id: `e-${lyricsTempId}-${musicTempId}`,
                         source: lyricsTempId,
                         target: musicTempId,
                         type: 'gradient',
                         animated: true
                     });

                     inputAssets.forEach(asset => {
                         if (asset.id) {
                             newEdges.push({
                                 id: `e-${asset.id}-${lyricsTempId}`,
                                 source: asset.id,
                                 target: lyricsTempId,
                                 type: 'gradient',
                                 animated: true
                             });
                         }
                     });
                     continue;
                 }

                 const tempId = `gen-temp-${Date.now()}-${i}`;
                 placeholderIds.push(tempId);

                 let nodeTitle = '生成';
                 let nodeType = NodeType.AUDIO_GENERATOR;

                 if (type === 'audio') {
                     nodeTitle = '音频生成';
                     nodeType = NodeType.AUDIO_GENERATOR;
                 } else if (type === 'music') {
                     const modelType = shouldGenerateMusic ? 'music' : 'lyrics';
                     nodeTitle = modelType === 'lyrics' ? '歌词生成' : '音乐生成';
                     nodeType = modelType === 'lyrics' ? NodeType.LYRICS_GENERATOR : NodeType.AUDIO_GENERATOR;
                 }

                 placeholders.push({
                     id: tempId,
                     type: 'appNode',
                     position: nodePos,
                     data: {
                         title: nodeTitle,
                         type: nodeType,
                         status: 'WORKING',
                         model,
                         prompt,
                         aspectRatio: settings.aspectRatio,
                         voice: settings.voice,
                         styleId: settings.styleId,
                         resolution: settings.resolution,
                         generationType:
                            type === 'music'
                                ? (shouldGenerateMusic ? 'music' : undefined)
                                : (type === 'audio' ? 'audio' : undefined),
                         inputAssets: inputAssets
                     }
                 });

                 // Create edges from input assets to the new node
                 inputAssets.forEach(asset => {
                     if (asset.id) {
                         newEdges.push({
                             id: `e-${asset.id}-${tempId}`,
                             source: asset.id,
                             target: tempId,
                             type: 'gradient',
                             animated: true
                         });
                     }
                 });
            }
        }
        
        setNodes((nds) => nds.concat(placeholders));
        if (newEdges.length > 0) {
            setEdges((eds) => [...eds, ...newEdges]);
        }

        try {
            if (type === 'image') {
                const urls = await generateImage(
                    prompt, model, inputImages,
                    {
                        aspectRatio: settings.aspectRatio,
                        count,
                        styleId: settings.styleId,
                        onTaskId: (taskId) => {
                            // Update node with taskId for cancellation
                            setNodes((nds) => nds.map((n) => {
                                if (placeholderIds.includes(n.id) && n.type === 'appNode') {
                                    return { ...n, data: { ...n.data, taskId } } as AppNodeType;
                                }
                                return n;
                            }));
                        }
                    }
                );

                if (urls && urls.length > 0) {
                    // Single node with multiple images
                    setNodes((nds) => nds.map((n) => {
                        if (placeholderIds.includes(n.id) && n.type === 'appNode') {
                             return {
                                ...n,
                                data: {
                                    ...n.data,
                                    status: NodeStatus.SUCCESS,
                                    image: urls[0],
                                    images: urls,
                                    taskId: undefined
                                }
                             } as AppNodeType;
                        }
                        return n;
                    }));

                    urls.forEach((url, index) => {
                         addGenerationHistoryItem({
                            id: `gen-${Date.now()}-${index}`,
                            type: 'image',
                            src: url,
                            title: prompt || 'Image Generation',
                            timestamp: Date.now(),
                            model,
                            context: generationContext
                        });
                    });
                }
            } else if (type === 'video') {
                // For video, use first image as main input, others as reference
                const inputImage = inputImages.length > 0 ? inputImages[0] : undefined;
                const referenceImages = inputImages.length > 1 ? inputImages.slice(1) : undefined;

                const res = await generateVideo(
                    prompt, model,
                    {
                        resolution: settings.resolution,
                        aspectRatio: settings.aspectRatio,
                        count,
                        onTaskId: (taskId) => {
                            // Update node with taskId for cancellation
                            setNodes((nds) => nds.map((n) => {
                                if (placeholderIds.includes(n.id) && n.type === 'appNode') {
                                    return { ...n, data: { ...n.data, taskId } } as AppNodeType;
                                }
                                return n;
                            }));
                        }
                    },
                    inputImage,
                    inputVideos.length > 0 ? inputVideos : undefined,
                    referenceImages,
                    undefined
                );

                const uris = res.uris || (res.uri ? [res.uri] : []);

                // Single node with multiple videos
                setNodes((nds) => nds.map((n) => {
                    if (placeholderIds.includes(n.id) && n.type === 'appNode') {
                         return {
                            ...n,
                            data: {
                                ...n.data,
                                status: NodeStatus.SUCCESS,
                                videoUri: uris[0],
                                videoUris: uris,
                                taskId: undefined
                            }
                         } as AppNodeType;
                    }
                    return n;
                }));

                uris.forEach((uri, index) => {
                   addGenerationHistoryItem({
                       id: `gen-${Date.now()}-${index}`,
                       type: 'video',
                       src: uri,
                       title: prompt || 'Video Generation',
                       timestamp: Date.now(),
                       model,
                       context: generationContext
                   });
                });
            } else if (type === 'audio') {
                const audioUrls = await Promise.all(
                    placeholderIds.map((nodeId) =>
                        generateAudio(prompt, {
                            model,
                            voice: settings.voice,
                            projectId: generationContext.assetId || undefined,
                            onTaskId: (taskId) => {
                                setNodes((nds) => nds.map((n) =>
                                    n.id === nodeId && n.type === 'appNode'
                                        ? { ...n, data: { ...n.data, taskId } } as AppNodeType
                                        : n
                                ));
                            },
                        })
                    )
                );

                setNodes((nds) => nds.map((n) => {
                    const idx = placeholderIds.indexOf(n.id);
                    if (idx !== -1 && audioUrls[idx] && n.type === 'appNode') {
                         return {
                            ...n,
                            data: { ...n.data, status: NodeStatus.SUCCESS, audioUri: audioUrls[idx], taskId: undefined }
                         } as AppNodeType;
                    }
                    return n;
                }));
                
                audioUrls.forEach((url, index) => {
                   addGenerationHistoryItem({
                       id: `gen-${Date.now()}-${index}`,
                       type: 'audio',
                       src: url,
                       title: prompt || 'Audio Generation',
                       timestamp: Date.now(),
                       model,
                       context: generationContext
                   });
                });
            } else if (type === 'music') {
                if (shouldGenerateLyrics && !shouldGenerateMusic) {
                    const lyricsResults = await Promise.all(
                        placeholderIds.map((nodeId, idx) =>
                            generateLyrics(prompt, {
                                model: resolvedLyricsModel,
                                mode: 'write_full_song',
                                projectId: generationContext.assetId || undefined,
                                onTaskId: (taskId) => {
                                    setNodes((nds) => nds.map((n) =>
                                        n.id === nodeId && n.type === 'appNode'
                                            ? { ...n, data: { ...n.data, taskId } } as AppNodeType
                                            : n
                                    ));
                                },
                            })
                        )
                    );

                    setNodes((nds) => nds.map((n) => {
                        const idx = placeholderIds.indexOf(n.id);
                        if (idx !== -1 && lyricsResults[idx] && n.type === 'appNode') {
                            return {
                                ...n,
                                data: {
                                    ...n.data,
                                    status: NodeStatus.SUCCESS,
                                    lyrics: lyricsResults[idx].lyrics,
                                    title: lyricsResults[idx].songTitle || n.data.title,
                                    taskId: undefined
                                }
                            } as AppNodeType;
                        }
                        return n;
                    }));
                } else if (!shouldGenerateLyrics && shouldGenerateMusic) {
                    const musicUrls = await Promise.all(
                        placeholderIds.map((nodeId, idx) =>
                            generateMusic(prompt, {
                                model: resolvedMusicModel,
                                projectId: generationContext.assetId || undefined,
                                onTaskId: (taskId) => {
                                    setNodes((nds) => nds.map((n) =>
                                        n.id === nodeId && n.type === 'appNode'
                                            ? { ...n, data: { ...n.data, taskId } } as AppNodeType
                                            : n
                                    ));
                                },
                            })
                        )
                    );

                    setNodes((nds) => nds.map((n) => {
                        const idx = placeholderIds.indexOf(n.id);
                        if (idx !== -1 && musicUrls[idx] && n.type === 'appNode') {
                             return {
                                ...n,
                                data: { ...n.data, status: NodeStatus.SUCCESS, audioUri: musicUrls[idx], taskId: undefined }
                             } as AppNodeType;
                        }
                        return n;
                    }));

                    musicUrls.forEach((url, index) => {
                        addGenerationHistoryItem({
                            id: `gen-${Date.now()}-${index}`,
                            type: 'audio',
                            src: url,
                            title: prompt || 'Music Generation',
                            timestamp: Date.now(),
                            model,
                            context: generationContext
                        });
                    });
                } else {
                    const lyricsResults = await Promise.all(
                        Array(count).fill(0).map(() =>
                            generateLyrics(prompt, {
                                model: resolvedLyricsModel,
                                mode: 'write_full_song',
                                projectId: generationContext.assetId || undefined,
                            })
                        )
                    );

                    const musicUrls = await Promise.all(
                        lyricsResults.map((result, idx) =>
                            generateMusic(result.lyrics, {
                                model: resolvedMusicModel,
                                prompt,
                                projectId: generationContext.assetId || undefined,
                                onTaskId: (taskId) => {
                                    const nodeId = musicPlaceholderIds[idx];
                                    setNodes((nds) => nds.map((n) =>
                                        n.id === nodeId && n.type === 'appNode'
                                            ? { ...n, data: { ...n.data, taskId } } as AppNodeType
                                            : n
                                    ));
                                },
                            })
                        )
                    );

                    setNodes((nds) => nds.map((n) => {
                        const lyricsIdx = lyricsPlaceholderIds.indexOf(n.id);
                        if (lyricsIdx !== -1 && lyricsResults[lyricsIdx] && n.type === 'appNode') {
                            return {
                                ...n,
                                data: {
                                    ...n.data,
                                    status: NodeStatus.SUCCESS,
                                    lyrics: lyricsResults[lyricsIdx].lyrics,
                                    title: lyricsResults[lyricsIdx].songTitle || n.data.title
                                }
                            } as AppNodeType;
                        }

                        const musicIdx = musicPlaceholderIds.indexOf(n.id);
                        if (musicIdx !== -1 && musicUrls[musicIdx] && n.type === 'appNode') {
                            return {
                                ...n,
                                data: {
                                    ...n.data,
                                    status: NodeStatus.SUCCESS,
                                    audioUri: musicUrls[musicIdx],
                                    taskId: undefined
                                }
                            } as AppNodeType;
                        }
                        return n;
                    }));

                    musicUrls.forEach((url, index) => {
                        addGenerationHistoryItem({
                            id: `gen-${Date.now()}-${index}`,
                            type: 'audio',
                            src: url,
                            title: prompt || 'Music Generation',
                            timestamp: Date.now(),
                            model: resolvedMusicModel,
                            context: generationContext
                        });
                    });
                }
            }
        } catch (e: any) {
            console.error("Interaction Generation Failed", e);
            const errorMsg = e?.message || 'Generation failed';
            const isCancelled = errorMsg === '已取消' || errorMsg.includes('cancel');
            setNodes((nds) => nds.map((n) => {
                if (placeholderIds.includes(n.id) && n.type === 'appNode') {
                    return {
                        ...n,
                        data: {
                            ...n.data,
                            status: isCancelled ? 'IDLE' : 'ERROR',
                            error: isCancelled ? '已取消' : errorMsg,
                            taskId: undefined
                        }
                    } as AppNodeType;
                }
                return n;
            }));
        }
    }, [screenToFlowPosition, getImageModelDefault, getVideoModelDefault, getAudioModelDefault, getMusicModelDefault, getLyricsModelDefault, saveContext, getNodes, setNodes, setEdges, addGenerationHistoryItem]);

    return {
        getImageModelDefault,
        getVideoModelDefault,
        getAudioModelDefault,
        getLLMModelDefault,
        handleAddNode,
        handleCreateAndConnect,
        handleSketchResult,
        handleInteractionGenerate
    };
};
