'use client';

import React, { memo, useState, useEffect, useRef, useCallback, useMemo } from 'react';
import dynamic from 'next/dynamic';
import { Node, NodeProps, Handle, Position, NodeResizeControl } from '@xyflow/react';
import { 
    Video, Type, Image as ImageIcon, 
    Edit, Mic2, Info, FileSearch, Sparkles, CirclePlus, ScrollText
} from 'lucide-react';
import { cn } from '@/utils';
import { AppNodeData, AppNodeType } from '../types/node';
import { useNodeData } from '../hooks/useNodeData';
import { useNodeExecution } from '../hooks/useNodeExecution';
import { useNodeDimensions } from '../hooks/useNodeDimensions';
import { useNodeDataSync } from '../hooks/useNodeDataSync';
import { useNodeActions } from '../hooks/useNodeActions';

import { NodeToolbar } from './components/NodeToolbar';
import { NodeHandles } from './components/NodeHandles';
import { NodeFrame } from './components/NodeFrame';

// Lazy load renderers to improve initial canvas load time
const PromptInputRenderer = dynamic(() => import('./renderers/PromptInputRenderer').then(m => m.PromptInputRenderer), {
    loading: () => <div className="absolute inset-0 flex items-center justify-center"><Sparkles className="animate-pulse text-muted-foreground/20" size={32} /></div>
});
const VideoAnalyzerRenderer = dynamic(() => import('./renderers/VideoAnalyzerRenderer').then(m => m.VideoAnalyzerRenderer), {
    loading: () => <div className="absolute inset-0 flex items-center justify-center"><FileSearch className="animate-pulse text-muted-foreground/20" size={32} /></div>
});
const AudioGeneratorRenderer = dynamic(() => import('./renderers/AudioGeneratorRenderer').then(m => m.AudioGeneratorRenderer), {
    loading: () => <div className="absolute inset-0 flex items-center justify-center"><Mic2 className="animate-pulse text-muted-foreground/20" size={32} /></div>
});
const MediaDisplayRenderer = dynamic(() => import('./renderers/MediaDisplayRenderer').then(m => m.MediaDisplayRenderer), {
    loading: () => <div className="absolute inset-0 flex items-center justify-center"><ImageIcon className="animate-pulse text-muted-foreground/20" size={32} /></div>
});
const InfoDisplayRenderer = dynamic(() => import('./renderers/InfoDisplayRenderer').then(m => m.InfoDisplayRenderer), {
    loading: () => <div className="absolute inset-0 flex items-center justify-center"><Info className="animate-pulse text-muted-foreground/20" size={32} /></div>
});
const PromptGeneratorRenderer = dynamic(() => import('./renderers/PromptGeneratorRenderer').then(m => m.PromptGeneratorRenderer), {
    loading: () => <div className="absolute inset-0 flex items-center justify-center"><Sparkles className="animate-pulse text-muted-foreground/20" size={32} /></div>
});
const LyricsGeneratorRenderer = dynamic(() => import('./renderers/LyricsGeneratorRenderer').then(m => m.LyricsGeneratorRenderer), {
    loading: () => <div className="absolute inset-0 flex items-center justify-center"><ScrollText className="animate-pulse text-muted-foreground/20" size={32} /></div>
});

type ConcreteAppNode = Node<AppNodeData, 'appNode'>;

const AppNodeComponent = ({ id, data, selected, dragging }: NodeProps<ConcreteAppNode>) => {
    const { update } = useNodeData(id);
    const { executeNode } = useNodeExecution();
    const { 
        type, 
        status = 'IDLE',
        title,
        prompt,
        userPrompt,
        model,
        inputPrompt,
        targetType,
        aspectRatio,
        resolution,
        duration,
        stylePrompt,
        styleId,
        imageCount,
        videoCount,
        template,
        image,
        videoUri,
        audioUri,
        content: nodeContent,
        autoExecute,
        images,
        videoUris,
        error,
        generationMode,
        croppedFrame,
        negativePrompt,
        shotType,
        enableAudio,
        cameraControl
    } = data;

    const [isResizing, setIsResizing] = useState(false);
    
    // Track if autoExecute has been processed to prevent double execution
    const autoExecuteProcessedRef = useRef(false);

    // Auto-execute logic: watch for autoExecute flag | 自动执行逻辑：监听 autoExecute 标志
    useEffect(() => {
        // Only execute if:
        // 1. autoExecute is true
        // 2. Node is not already working
        // 3. Node type supports execution (generators)
        // 4. Haven't processed this autoExecute yet
        const isGeneratorNode = ['IMAGE_GENERATOR', 'VIDEO_GENERATOR', 'AUDIO_GENERATOR', 'IMAGE_EDITOR', 'PROMPT_GENERATOR', 'VIDEO_ANALYZER', 'LYRICS_GENERATOR'].includes(type);
        
        if (autoExecute && status !== 'WORKING' && isGeneratorNode && !autoExecuteProcessedRef.current) {
            autoExecuteProcessedRef.current = true;
            
            // Clear the autoExecute flag first to prevent re-triggering
            update({ autoExecute: false });
            
            // Delay execution slightly to ensure node connections are established
            const timer = setTimeout(() => {
                executeNode(id);
            }, 150);
            
            return () => clearTimeout(timer);
        }
        
        // Reset the processed flag when autoExecute becomes false
        if (!autoExecute) {
            autoExecuteProcessedRef.current = false;
        }
    }, [autoExecute, status, type, id, update, executeNode]);


    // 1. Node Dimensions Logic
    const { 
        nodeWidth, 
        nodeHeight, 
        minHeight, 
        shouldKeepRatio,
        ratio: _ratio, // used internally in hook, but available if needed
        aspectW: _aspectW,
        aspectH: _aspectH
    } = useNodeDimensions(data);

    // 2. Data Synchronization Logic
    const { 
        inputAssets, 
        handleInputReorder 
    } = useNodeDataSync(id, data, update);

    // 3. Node Actions Logic
    const {
        handleDownload,
        handleExpand,
        handleMediaContextMenu,
        handleCropRequest,
        handleSmartSave,
        handleHandleClick
    } = useNodeActions(id, data, update);

    const [isHovered, setIsHovered] = useState(false);
    const isWorking = status === 'WORKING';

    const handleMouseEnter = useCallback(() => setIsHovered(true), []);
    const handleMouseLeave = useCallback(() => setIsHovered(false), []);
    const handleResizeStart = useCallback(() => setIsResizing(true), []);
    const handleResizeEnd = useCallback(() => setIsResizing(false), []);
    const handleResize = useCallback((width: number) => update({ width }), [update]);
    const handleExecute = useCallback(() => executeNode(id), [executeNode, id]);

    const nodeConfig = useMemo(() => {
        switch (type) {
            case 'PROMPT_INPUT': return { icon: Type, color: 'text-amber-400', border: 'border-amber-500/30', ring: 'ring-amber-500/50', shadow: 'shadow-[0_0_40px_-10px_rgba(245,158,11,0.3)]', accent: 'amber' as const };
            case 'LYRICS_GENERATOR': return { icon: ScrollText, color: 'text-indigo-400', border: 'border-indigo-500/30', ring: 'ring-indigo-500/50', shadow: 'shadow-[0_0_40px_-10px_rgba(99,102,241,0.3)]', accent: 'indigo' as const };
            case 'IMAGE_GENERATOR': return { icon: ImageIcon, color: 'text-cyan-400', border: 'border-cyan-500/30', ring: 'ring-cyan-500/50', shadow: 'shadow-[0_0_40px_-10px_rgba(34,211,238,0.3)]', accent: 'cyan' as const };
            case 'VIDEO_GENERATOR': return { icon: Video, color: 'text-purple-400', border: 'border-purple-500/30', ring: 'ring-purple-500/50', shadow: 'shadow-[0_0_40px_-10px_rgba(192,132,252,0.3)]', accent: 'purple' as const };
            case 'AUDIO_GENERATOR': return { icon: Mic2, color: 'text-pink-400', border: 'border-pink-500/30', ring: 'ring-pink-500/50', shadow: 'shadow-[0_0_40px_-10px_rgba(244,114,182,0.3)]', accent: 'pink' as const };
            case 'VIDEO_ANALYZER': return { icon: FileSearch, color: 'text-emerald-400', border: 'border-emerald-500/30', ring: 'ring-emerald-500/50', shadow: 'shadow-[0_0_40px_-10px_rgba(52,211,153,0.3)]', accent: 'emerald' as const };
            case 'IMAGE_EDITOR': return { icon: Edit, color: 'text-rose-400', border: 'border-rose-500/30', ring: 'ring-rose-500/50', shadow: 'shadow-[0_0_40px_-10px_rgba(251,113,133,0.3)]', accent: 'rose' as const };
            case 'INFO_DISPLAY': return { icon: Info, color: 'text-blue-400', border: 'border-blue-500/30', ring: 'ring-blue-500/50', shadow: 'shadow-[0_0_40px_-10px_rgba(96,165,250,0.3)]', accent: 'blue' as const };
            case 'PROMPT_GENERATOR': return { icon: Sparkles, color: 'text-fuchsia-400', border: 'border-fuchsia-500/30', ring: 'ring-fuchsia-500/50', shadow: 'shadow-[0_0_40px_-10px_rgba(232,121,249,0.3)]', accent: 'fuchsia' as const };
            default: return { icon: Type, color: 'text-muted-foreground', border: 'border-white/10', ring: 'ring-white/50', shadow: 'shadow-[0_0_40px_-10px_rgba(255,255,255,0.3)]', accent: 'cyan' as const };
        }
    }, [type]);

    const { icon: NodeIcon, ring: ringColor, shadow: shadowColor, accent: loadingAccent } = nodeConfig;

    const content = useMemo(() => {
        switch (type) {
            case 'PROMPT_INPUT':
                return <PromptInputRenderer data={data} update={update} />;
            case 'LYRICS_GENERATOR':
                return <LyricsGeneratorRenderer data={data} isWorking={isWorking} loadingAccent={loadingAccent} />;
            case 'VIDEO_ANALYZER':
                return <VideoAnalyzerRenderer data={data} update={update} isWorking={isWorking} onExpand={handleExpand} loadingAccent={loadingAccent} />;
            case 'AUDIO_GENERATOR':
                return <AudioGeneratorRenderer data={data} isWorking={isWorking} update={update} loadingAccent={loadingAccent} />;
            case 'INFO_DISPLAY':
                return <InfoDisplayRenderer data={data} title={data.title} />;
            case 'PROMPT_GENERATOR':
                return <PromptGeneratorRenderer data={data} isWorking={isWorking} loadingAccent={loadingAccent} />;
            default:
                return <MediaDisplayRenderer 
                    type={type}
                    loadingAccent={loadingAccent}
                    image={image}
                    videoUri={videoUri}
                    images={images}
                    videoUris={videoUris}
                    content={nodeContent}
                    title={title}
                    error={error}
                    generationMode={generationMode}
                    croppedFrame={croppedFrame}
                    inputAssets={inputAssets}
                    isWorking={isWorking} 
                    onExpand={handleExpand} 
                    icon={NodeIcon} 
                    update={update} 
                    onCropRequest={handleCropRequest}
                    onContextMenu={handleMediaContextMenu}
                />;
        }
    }, [
        type,
        data,
        update,
        isWorking,
        handleExpand,
        NodeIcon,
        loadingAccent,
        handleCropRequest,
        handleMediaContextMenu,
        image,
        videoUri,
        images,
        videoUris,
        nodeContent,
        title,
        error,
        generationMode,
        croppedFrame,
        inputAssets,
    ]);

    const handleUpdateTitle = useCallback((newTitle: string) => update({ title: newTitle }), [update]);

    return (
        <NodeFrame
            selected={selected}
            dragging={dragging}
            isResizing={isResizing}
            isHovered={isHovered}
            width={nodeWidth}
            height={nodeHeight}
            minHeight={minHeight}
            shouldKeepRatio={shouldKeepRatio}
            ringColor={ringColor}
            shadowColor={shadowColor}
            onMouseEnter={handleMouseEnter}
            onMouseLeave={handleMouseLeave}
            onResizeStart={handleResizeStart}
            onResizeEnd={handleResizeEnd}
            onResize={handleResize}
            toolbar={
                <NodeToolbar 
                    title={title}
                    type={type}
                    hasMedia={!!(image || videoUri || audioUri || nodeContent)}
                    updateTitle={handleUpdateTitle}
                    selected={selected} 
                    isHovered={isHovered} 
                    isWorking={isWorking}
                    onSave={handleSmartSave}
                    onDownload={handleDownload}
                    onExpand={handleExpand}
                />
            }
            handles={<NodeHandles onHandleClick={handleHandleClick} />}
            controlPanel={null}
        >
            {content}
        </NodeFrame>
    );
};


// Custom Comparator for React.memo to prevent unnecessary re-renders during drag
const arePropsEqual = (prev: NodeProps<AppNodeType>, next: NodeProps<AppNodeType>) => {
    if (prev.selected !== next.selected || 
        prev.dragging !== next.dragging ||
        prev.zIndex !== next.zIndex ||
        prev.isConnectable !== next.isConnectable) {
        return false;
    }
    if (prev.data !== next.data) {
        return false;
    }
    return true;
};

export const AppNode = memo(AppNodeComponent, arePropsEqual);
