import { useMitt } from '@/plugins/MittContext';
import { useCallback, useEffect, useRef, useState } from 'react';
import { Image, Layer, Line, Stage, Text, Transformer } from 'react-konva';

const VideoPreview = ({
    // Dimensions
    dimensions,

    // Timeline state
    currentTime,
    totalDuration,
    isPlaying,
    status,

    // Export state
    isExporting,
    exportProgress,
    exportStatus,

    // Data
    timelineElements,
    activeElements,
    videoElements,
    loadedVideos,
    videoStates,
    ffmpegCommand,

    // Event handlers
    handlePlay,
    handlePause,
    handleReset,
    handleSeek,
    copyFFmpegCommand,
    exportVideo,
    onElementUpdate, // New prop for updating element properties

    // Refs
    layerRef,
}) => {
    const emitter = useMitt();

    // Selection state
    const [selectedElementId, setSelectedElementId] = useState(null);
    const transformerRef = useRef(null);
    const stageRef = useRef(null);

    // Refs for each element to connect with transformer
    const elementRefs = useRef({});

    // Guide lines state
    const [guideLines, setGuideLines] = useState({
        vertical: null,
        horizontal: null,
        showVertical: false,
        showHorizontal: false,
    });

    // Snap settings
    const POSITION_SNAP_THRESHOLD = 10; // Pixels within which to snap to center

    // Function to determine which image source to use for videos
    const getImageSource = (element) => {
        const isVideoActive = videoStates[element.id] && isPlaying;

        if (isVideoActive && element.videoElement && element.isVideoReady) {
            return element.videoElement;
        } else if (element.posterImage && element.isVideoPoster) {
            return element.posterImage;
        }

        return null;
    };

    // Helper function to get font style for text elements
    const getTextFontStyle = (element) => {
        const isBold = element.fontWeight === 'bold' || element.fontWeight === 700;
        const isItalic = element.fontStyle === 'italic';

        if (isBold && isItalic) {
            return 'bold italic';
        } else if (isBold) {
            return 'bold';
        } else if (isItalic) {
            return 'italic';
        } else {
            return 'normal';
        }
    };

    // Check if element uses center-offset positioning
    const usesCenterPositioning = (elementType) => {
        return elementType === 'video' || elementType === 'image';
    };

    // Check if position should snap to center and calculate guide lines
    const calculateSnapAndGuides = (elementId, newX, newY, width, height) => {
        const centerX = dimensions.width / 2;
        const centerY = dimensions.height / 2;

        // Calculate element center
        const elementCenterX = newX + width / 2;
        const elementCenterY = newY + height / 2;

        let snapX = newX;
        let snapY = newY;
        let showVertical = false;
        let showHorizontal = false;
        let verticalLine = null;
        let horizontalLine = null;

        // Check vertical center snap
        if (Math.abs(elementCenterX - centerX) < POSITION_SNAP_THRESHOLD) {
            snapX = centerX - width / 2;
            showVertical = true;
            verticalLine = centerX;
        }

        // Check horizontal center snap
        if (Math.abs(elementCenterY - centerY) < POSITION_SNAP_THRESHOLD) {
            snapY = centerY - height / 2;
            showHorizontal = true;
            horizontalLine = centerY;
        }

        return {
            x: snapX,
            y: snapY,
            guideLines: {
                vertical: verticalLine,
                horizontal: horizontalLine,
                showVertical,
                showHorizontal,
            },
        };
    };

    // Handle element selection
    const handleElementSelect = useCallback(
        (elementId) => {
            setSelectedElementId(elementId);

            // Find the selected element
            const element = timelineElements.find((el) => el.id === elementId);

            // If it's a text element, emit text-element-selected event
            if (element && element.type === 'text') {
                emitter.emit('text-element-selected', element);
            }

            // Clear guide lines when selecting
            setGuideLines({
                vertical: null,
                horizontal: null,
                showVertical: false,
                showHorizontal: false,
            });
        },
        [emitter, timelineElements],
    );

    // Handle clicking on empty space to deselect
    const handleStageClick = useCallback((e) => {
        // If clicking on stage (not on an element), deselect
        if (e.target === e.target.getStage()) {
            setSelectedElementId(null);
            setGuideLines({
                vertical: null,
                horizontal: null,
                showVertical: false,
                showHorizontal: false,
            });
        }
    }, []);

    // Handle drag events with snapping
    const handleDragMove = useCallback(
        (elementId, e) => {
            const node = e.target;
            const element = timelineElements.find((el) => el.id === elementId);
            if (!element) return;

            const width = node.width() * node.scaleX();
            const height = node.height() * node.scaleY();

            let topLeftX, topLeftY;

            if (usesCenterPositioning(element.type)) {
                // For center-positioned elements (video/image), convert center to top-left
                const elementCenterX = node.x();
                const elementCenterY = node.y();
                topLeftX = elementCenterX - width / 2;
                topLeftY = elementCenterY - height / 2;
            } else {
                // For top-left positioned elements (text)
                topLeftX = node.x();
                topLeftY = node.y();
            }

            const snapResult = calculateSnapAndGuides(elementId, topLeftX, topLeftY, width, height);

            // Update guide lines
            setGuideLines(snapResult.guideLines);

            // Update state during drag
            if (onElementUpdate) {
                onElementUpdate(elementId, {
                    x: snapResult.x,
                    y: snapResult.y,
                });
            }
        },
        [onElementUpdate, dimensions.width, dimensions.height, timelineElements],
    );

    // Create drag bound function for real-time snapping
    const createDragBoundFunc = useCallback(
        (elementId) => {
            return (pos) => {
                const element = timelineElements.find((el) => el.id === elementId);
                if (!element) return pos;

                const node = elementRefs.current[elementId];
                if (!node) return pos;

                const width = node.width() * node.scaleX();
                const height = node.height() * node.scaleY();

                let topLeftX, topLeftY;

                if (usesCenterPositioning(element.type)) {
                    // Convert center position to top-left for snapping calculations
                    topLeftX = pos.x - width / 2;
                    topLeftY = pos.y - height / 2;
                } else {
                    topLeftX = pos.x;
                    topLeftY = pos.y;
                }

                const snapResult = calculateSnapAndGuides(elementId, topLeftX, topLeftY, width, height);

                if (usesCenterPositioning(element.type)) {
                    // Convert back to center position
                    return {
                        x: snapResult.x + width / 2,
                        y: snapResult.y + height / 2,
                    };
                } else {
                    return {
                        x: snapResult.x,
                        y: snapResult.y,
                    };
                }
            };
        },
        [timelineElements, dimensions.width, dimensions.height],
    );

    const handleDragEnd = useCallback(
        (elementId, e) => {
            const node = e.target;
            const element = timelineElements.find((el) => el.id === elementId);
            if (!element) return;

            // Clear guide lines when drag ends
            setGuideLines({
                vertical: null,
                horizontal: null,
                showVertical: false,
                showHorizontal: false,
            });

            // Final position update
            const width = node.width() * node.scaleX();
            const height = node.height() * node.scaleY();

            let finalX, finalY;
            if (usesCenterPositioning(element.type)) {
                finalX = node.x() - width / 2;
                finalY = node.y() - height / 2;
            } else {
                finalX = node.x();
                finalY = node.y();
            }

            if (onElementUpdate) {
                onElementUpdate(elementId, {
                    x: finalX,
                    y: finalY,
                });
            }
        },
        [onElementUpdate, timelineElements],
    );

    // Handle transform events - TRANSFORMER IS SOURCE OF TRUTH
    const handleTransform = useCallback(
        (elementId) => {
            const node = elementRefs.current[elementId];
            const element = timelineElements.find((el) => el.id === elementId);
            if (!node || !onElementUpdate || !element) return;

            // Get rotation - Konva handles snapping automatically with rotationSnaps
            const rotation = node.rotation();

            // Get the scale values from Konva
            const scaleX = node.scaleX();
            const scaleY = node.scaleY();

            let newWidth, newHeight;
            let updates = { rotation };

            if (element.type === 'text') {
                // For text: Convert scale to actual fontSize and reset scale to 1
                const avgScale = Math.max(Math.abs(scaleX), Math.abs(scaleY));
                const newFontSize = Math.round(element.fontSize * avgScale);

                // Clamp font size to reasonable limits
                const clampedFontSize = Math.max(8, Math.min(120, newFontSize));

                updates.fontSize = clampedFontSize;

                // Reset scale to 1 since we've applied it to fontSize
                node.scaleX(1);
                node.scaleY(1);

                // Text dimensions are handled by Konva based on content and fontSize
                newWidth = node.width();
                newHeight = node.height();
            } else {
                // For images/videos, maintain aspect ratio by using the larger scale
                const scale = Math.max(Math.abs(scaleX), Math.abs(scaleY));
                newWidth = node.width() * scale;
                newHeight = node.height() * scale;

                // Reset scale to 1 and update dimensions to maintain aspect ratio
                node.scaleX(1);
                node.scaleY(1);
                node.width(newWidth);
                node.height(newHeight);

                // Update offset for center rotation
                node.offsetX(newWidth / 2);
                node.offsetY(newHeight / 2);

                updates.width = newWidth;
                updates.height = newHeight;
            }

            // Calculate position for snapping
            let topLeftX, topLeftY;

            if (usesCenterPositioning(element.type)) {
                // Convert center position to top-left for snapping
                const centerX = node.x();
                const centerY = node.y();
                topLeftX = centerX - newWidth / 2;
                topLeftY = centerY - newHeight / 2;
            } else {
                // Use position directly for text
                topLeftX = node.x();
                topLeftY = node.y();
            }

            // Check for position snapping during transform (but be less aggressive during rotation)
            const isRotating = Math.abs(rotation % 90) > 5; // Not close to perpendicular
            if (!isRotating) {
                const snapResult = calculateSnapAndGuides(elementId, topLeftX, topLeftY, newWidth, newHeight);

                if (Math.abs(snapResult.x - topLeftX) > 5 || Math.abs(snapResult.y - topLeftY) > 5) {
                    if (usesCenterPositioning(element.type)) {
                        // Convert back to center position
                        const newCenterX = snapResult.x + newWidth / 2;
                        const newCenterY = snapResult.y + newHeight / 2;
                        node.x(newCenterX);
                        node.y(newCenterY);
                    } else {
                        // Apply directly for text
                        node.x(snapResult.x);
                        node.y(snapResult.y);
                    }
                    setGuideLines(snapResult.guideLines);
                    topLeftX = snapResult.x;
                    topLeftY = snapResult.y;
                }
            } else {
                // Clear guide lines during rotation
                setGuideLines({
                    vertical: null,
                    horizontal: null,
                    showVertical: false,
                    showHorizontal: false,
                });
            }

            // Add position to updates
            updates.x = topLeftX;
            updates.y = topLeftY;

            // Update state with all calculated values
            onElementUpdate(elementId, updates);
        },
        [onElementUpdate, dimensions.width, dimensions.height, timelineElements],
    );

    // Update transformer when selection changes
    useEffect(() => {
        if (transformerRef.current) {
            const selectedNode = selectedElementId ? elementRefs.current[selectedElementId] : null;

            if (selectedNode) {
                transformerRef.current.nodes([selectedNode]);
                transformerRef.current.getLayer().batchDraw();
            } else {
                transformerRef.current.nodes([]);
            }
        }
    }, [selectedElementId, activeElements]);

    return (
        <div>
            <Stage width={dimensions.width} height={dimensions.height} ref={stageRef} onClick={handleStageClick} onTap={handleStageClick}>
                <Layer ref={layerRef}>
                    {activeElements.map((element) => {
                        const isSelected = selectedElementId === element.id;

                        if (element.type === 'video') {
                            const imageSource = getImageSource(element);

                            if (!imageSource) {
                                return null;
                            }

                            return (
                                <Image
                                    key={element.id}
                                    ref={(node) => {
                                        if (node) {
                                            elementRefs.current[element.id] = node;
                                        }
                                    }}
                                    image={imageSource}
                                    // Use center position for x,y when offset is set
                                    x={element.x + element.width / 2}
                                    y={element.y + element.height / 2}
                                    width={element.width}
                                    height={element.height}
                                    // Set offset to center for proper rotation
                                    offsetX={element.width / 2}
                                    offsetY={element.height / 2}
                                    rotation={element.rotation || 0}
                                    draggable
                                    dragBoundFunc={createDragBoundFunc(element.id)}
                                    onClick={() => handleElementSelect(element.id)}
                                    onTap={() => handleElementSelect(element.id)}
                                    onDragMove={(e) => handleDragMove(element.id, e)}
                                    onDragEnd={(e) => handleDragEnd(element.id, e)}
                                    onTransform={() => handleTransform(element.id)}
                                    // Visual feedback for selection
                                    stroke={isSelected ? '#0066ff' : undefined}
                                    strokeWidth={isSelected ? 2 : 0}
                                    strokeScaleEnabled={false}
                                />
                            );
                        } else if (element.type === 'text') {
                            return (
                                <Text
                                    key={element.id}
                                    ref={(node) => {
                                        if (node) {
                                            elementRefs.current[element.id] = node;
                                        }
                                    }}
                                    text={element.text}
                                    x={element.x}
                                    y={element.y}
                                    fontSize={element.fontSize}
                                    fontStyle={getTextFontStyle(element)}
                                    fontFamily={element.fontFamily || 'Arial'}
                                    fill={element.fill || '#ffffff'}
                                    stroke={element.strokeWidth > 0 ? element.stroke || '#000000' : undefined}
                                    strokeWidth={element.strokeWidth * 3 || 0}
                                    fillAfterStrokeEnabled={true}
                                    strokeScaleEnabled={false}
                                    rotation={element.rotation || 0}
                                    // Center the text horizontally
                                    align="center"
                                    // Let text have natural width and height for multiline support
                                    wrap="word"
                                    // Always scale 1 - size changes go through fontSize
                                    scaleX={1}
                                    scaleY={1}
                                    draggable
                                    dragBoundFunc={createDragBoundFunc(element.id)}
                                    onClick={() => handleElementSelect(element.id)}
                                    onTap={() => handleElementSelect(element.id)}
                                    onDragMove={(e) => handleDragMove(element.id, e)}
                                    onDragEnd={(e) => handleDragEnd(element.id, e)}
                                    onTransform={() => handleTransform(element.id)}
                                    // Visual feedback for selection
                                />
                            );
                        } else if (element.type === 'image' && element.imageElement && element.isImageReady) {
                            return (
                                <Image
                                    key={element.id}
                                    ref={(node) => {
                                        if (node) {
                                            elementRefs.current[element.id] = node;
                                        }
                                    }}
                                    image={element.imageElement}
                                    // Use center position for x,y when offset is set
                                    x={element.x + element.width / 2}
                                    y={element.y + element.height / 2}
                                    width={element.width}
                                    height={element.height}
                                    // Set offset to center for proper rotation
                                    offsetX={element.width / 2}
                                    offsetY={element.height / 2}
                                    rotation={element.rotation || 0}
                                    draggable
                                    dragBoundFunc={createDragBoundFunc(element.id)}
                                    onClick={() => handleElementSelect(element.id)}
                                    onTap={() => handleElementSelect(element.id)}
                                    onDragMove={(e) => handleDragMove(element.id, e)}
                                    onDragEnd={(e) => handleDragEnd(element.id, e)}
                                    onTransform={() => handleTransform(element.id)}
                                    // Visual feedback for selection
                                    stroke={isSelected ? '#0066ff' : undefined}
                                    strokeWidth={isSelected ? 2 : 0}
                                    strokeScaleEnabled={false}
                                />
                            );
                        }
                        return null;
                    })}

                    {/* Guide Lines Layer */}
                    {guideLines.showVertical && (
                        <Line
                            points={[guideLines.vertical, 0, guideLines.vertical, dimensions.height]}
                            stroke="#0066ff"
                            strokeWidth={1}
                            dash={[4, 4]}
                            opacity={0.8}
                            listening={false}
                        />
                    )}
                    {guideLines.showHorizontal && (
                        <Line
                            points={[0, guideLines.horizontal, dimensions.width, guideLines.horizontal]}
                            stroke="#0066ff"
                            strokeWidth={1}
                            dash={[4, 4]}
                            opacity={0.8}
                            listening={false}
                        />
                    )}

                    {/* Transformer for selected element */}
                    <Transformer
                        ref={transformerRef}
                        boundBoxFunc={(oldBox, newBox) => {
                            // Limit resize to prevent elements from becoming too small
                            if (newBox.width < 20 || newBox.height < 20) {
                                return oldBox;
                            }
                            return newBox;
                        }}
                        // Transformer styling - Figma-like appearance
                        borderStroke="#0066ff"
                        borderStrokeWidth={2}
                        anchorStroke="#0066ff"
                        anchorFill="white"
                        anchorSize={14}
                        anchorCornerRadius={2}
                        // Enable only corner anchors for aspect ratio
                        enabledAnchors={['top-left', 'top-right', 'bottom-right', 'bottom-left']}
                        // Rotation handle
                        rotateAnchorOffset={30}
                        // Built-in Konva rotation snapping
                        rotationSnaps={[0, 90, 180, 270]}
                        rotationSnapTolerance={8}
                        // Clear guide lines when transform ends
                        onTransformEnd={() => {
                            setGuideLines({
                                vertical: null,
                                horizontal: null,
                                showVertical: false,
                                showHorizontal: false,
                            });
                        }}
                        // Style the rotation anchor to be circular
                        anchorStyleFunc={(anchor) => {
                            if (anchor.hasName('.rotater')) {
                                // Make it circular by setting corner radius to half the width
                                anchor.cornerRadius(anchor.width() / 2);
                                anchor.fill('#0066ff');
                                anchor.stroke('white');
                                anchor.strokeWidth(1);
                            }
                        }}
                    />
                </Layer>
            </Stage>
        </div>
    );
};

export default VideoPreview;
