import { useRef, useEffect, useCallback, useState } from 'react';
import { Stage, Layer, Rect, Line, Group, Text, Transformer } from 'react-konva';
import Konva from 'konva';
import { useLayoutStore, ROOM_COLORS, LayoutRoom } from '../../../stores/layoutStore';
import { layoutApi } from '../../../lib/layoutApi';
import { useToast } from '../../../context/ToastContext';

const PIXELS_PER_FOOT = 20; // 20 pixels = 1 foot

export function LayoutCanvas() {
    const containerRef = useRef<HTMLDivElement>(null);
    const stageRef = useRef<Konva.Stage>(null);
    const transformerRef = useRef<Konva.Transformer>(null);

    const [stageSize, setStageSize] = useState({ width: 800, height: 600 });
    const [isDragging, setIsDragging] = useState(false);

    const {
        zoom, pan, setPan,
        showGrid, snapToGrid, gridSize,
        rooms, sections, selectedIds, hoveredId,
        activeTool, pendingRoomType,
        select, clearSelection, setHovered,
        addRoom, moveRoom, resizeRoom,
        floorId,
        loadSections,
        setSelectedPosition,
    } = useLayoutStore();

    const { addToast } = useToast();

    // Resize handler
    useEffect(() => {
        const container = containerRef.current;
        if (!container) return;

        const updateSize = () => {
            setStageSize({
                width: container.offsetWidth,
                height: container.offsetHeight,
            });
        };

        updateSize();
        const observer = new ResizeObserver(updateSize);
        observer.observe(container);
        return () => observer.disconnect();
    }, []);

    // Update transformer when selection changes
    useEffect(() => {
        const transformer = transformerRef.current;
        const stage = stageRef.current;
        if (!transformer || !stage) return;

        const nodes = selectedIds
            .map(id => stage.findOne(`#room-${id}`) || stage.findOne(`#section-${id}`)) // Support sections
            .filter(Boolean) as Konva.Node[];

        transformer.nodes(nodes);
    }, [selectedIds]);

    // Grid lines
    const renderGrid = useCallback(() => {
        if (!showGrid) return null;

        const lines = [];
        const gridPx = gridSize * PIXELS_PER_FOOT;
        const viewWidth = stageSize.width / zoom + Math.abs(pan.x);
        const viewHeight = stageSize.height / zoom + Math.abs(pan.y);

        // Vertical lines
        for (let x = 0; x < viewWidth; x += gridPx) {
            const isMajor = (x / gridPx) % 10 === 0;
            lines.push(
                <Line
                    key={`v-${x}`}
                    points={[x, 0, x, viewHeight]}
                    stroke={isMajor ? 'rgba(255,255,255,0.15)' : 'rgba(255,255,255,0.05)'}
                    strokeWidth={1 / zoom}
                />
            );
        }

        // Horizontal lines
        for (let y = 0; y < viewHeight; y += gridPx) {
            const isMajor = (y / gridPx) % 10 === 0;
            lines.push(
                <Line
                    key={`h-${y}`}
                    points={[0, y, viewWidth, y]}
                    stroke={isMajor ? 'rgba(255,255,255,0.15)' : 'rgba(255,255,255,0.05)'}
                    strokeWidth={1 / zoom}
                />
            );
        }

        return lines;
    }, [showGrid, gridSize, pan, zoom, stageSize]);

    // Handle canvas click for adding rooms
    const handleStageClick = (e: Konva.KonvaEventObject<MouseEvent>) => {
        // If clicking on empty space, clear selection
        if (e.target === e.target.getStage()) {
            clearSelection();

            // If room tool is active, add a room
            if (activeTool === 'room' && pendingRoomType) {
                const stage = stageRef.current;
                if (!stage) return;

                const pointer = stage.getPointerPosition();
                if (!pointer) return;

                // Convert screen position to canvas position
                const x = (pointer.x - pan.x) / zoom;
                const y = (pointer.y - pan.y) / zoom;

                // Snap to grid
                const snappedX = snapToGrid
                    ? Math.round(x / (gridSize * PIXELS_PER_FOOT)) * (gridSize * PIXELS_PER_FOOT)
                    : x;
                const snappedY = snapToGrid
                    ? Math.round(y / (gridSize * PIXELS_PER_FOOT)) * (gridSize * PIXELS_PER_FOOT)
                    : y;

                const newId = addRoom({
                    name: `New ${pendingRoomType} Room`,
                    code: `${pendingRoomType.slice(0, 3).toUpperCase()}-${rooms.length + 1}`,
                    type: pendingRoomType,
                    floorId: floorId || 'default',
                    position: { x: snappedX, y: snappedY },
                    size: { width: 400, height: 300 }, // 20ft x 15ft default
                    rotation: 0,
                });

                select([newId]);
            }
        }
    };

    // Handle stage drag for panning
    const handleDragStart = () => setIsDragging(true);
    const handleDragEnd = () => setIsDragging(false);

    // Handle wheel for zoom
    const handleWheel = (e: Konva.KonvaEventObject<WheelEvent>) => {
        e.evt.preventDefault();

        const stage = stageRef.current;
        if (!stage) return;

        const oldZoom = zoom;
        const pointer = stage.getPointerPosition();
        if (!pointer) return;

        const mousePointTo = {
            x: (pointer.x - pan.x) / oldZoom,
            y: (pointer.y - pan.y) / oldZoom,
        };

        const newZoom = e.evt.deltaY > 0 ? oldZoom * 0.9 : oldZoom * 1.1;
        const boundedZoom = Math.max(0.1, Math.min(5, newZoom));

        useLayoutStore.setState({ zoom: boundedZoom });

        const newPos = {
            x: pointer.x - mousePointTo.x * boundedZoom,
            y: pointer.y - mousePointTo.y * boundedZoom,
        };

        setPan(newPos);
    };

    const handleDragOver = (e: React.DragEvent) => {
        e.preventDefault(); // Allow drop
    };

    const handleDrop = async (e: React.DragEvent) => {
        e.preventDefault();
        const data = e.dataTransfer.getData('application/json');
        if (!data) return;

        try {
            const parsed = JSON.parse(data);

            // Calculate Stage Coords
            const containerRect = containerRef.current?.getBoundingClientRect();
            if (!containerRect) return;

            const stageX = e.clientX - containerRect.left;
            const stageY = e.clientY - containerRect.top;

            const worldX = (stageX - pan.x) / zoom;
            const worldY = (stageY - pan.y) / zoom;

            // Find Section under cursor
            const targetSection = sections.find(s =>
                worldX >= s.position.x && worldX <= s.position.x + s.size.width &&
                worldY >= s.position.y && worldY <= s.position.y + s.size.height
            );

            if (!targetSection) {
                addToast('Drop target not found', 'warning');
                return;
            }

            // Calculate target position (row/col)
            const relX = worldX - targetSection.position.x;
            const relY = worldY - targetSection.position.y;
            const cellW = targetSection.size.width / targetSection.columns;
            const cellH = targetSection.size.height / targetSection.rows;
            const col = Math.ceil(relX / cellW);
            const row = Math.ceil(relY / cellH);

            // Handle PLANT move
            if (parsed.type === 'PLANT') {
                const { plantId, address: fromAddress } = parsed;

                if (col >= 1 && col <= targetSection.columns && row >= 1 && row <= targetSection.rows) {
                    const targetPos = targetSection.positions?.find(p => p.row === row && p.column === col);

                    if (!targetPos) {
                        addToast('Target slot not found', 'error');
                        return;
                    }

                    if (targetPos.status === 'PLANTED') {
                        addToast('Target slot is already occupied', 'warning');
                        return;
                    }

                    const result = await layoutApi.movePlant(plantId, targetPos.id);
                    addToast(`Moved plant to ${result.newAddress}`, 'success');
                }
            }
            // Handle BATCH placement
            else if (parsed.type === 'BATCH') {
                const batchId = parsed.id;
                const batchName = parsed.name || 'Batch';

                // Bulk fill mode: when zoomed out OR holding Shift key
                const isBulkMode = zoom <= 0.6 || e.shiftKey;

                if (isBulkMode) {
                    const result = await layoutApi.fillSection(targetSection.id, batchId);
                    addToast(`Placed ${result.plantsCreated} plants from ${batchName}`, 'success');
                } else {
                    if (col >= 1 && col <= targetSection.columns && row >= 1 && row <= targetSection.rows) {
                        const position = targetSection.positions?.find(p => p.row === row && p.column === col);

                        if (position && (position.status === 'EMPTY' || position.status === 'RESERVED')) {
                            await layoutApi.placeBatchInPosition(position.id, batchId);
                            addToast(`Placed ${batchName} at R${row}C${col}`, 'success');
                        } else if (position?.status === 'PLANTED') {
                            addToast('Slot already occupied', 'warning');
                            return;
                        }
                    }
                }
            }

            // Refresh Sections for this room
            const apiSections = await layoutApi.getRoomSections(targetSection.roomId);
            loadSections(apiSections.map(s => ({
                id: s.id,
                roomId: s.roomId,
                name: s.name,
                code: s.code,
                type: s.type as any,
                position: { x: s.posX, y: s.posY },
                size: { width: s.width, height: s.height },
                rows: s.rows,
                columns: s.columns,
                spacing: s.spacing || 12,
                positions: s.positions as any
            })));
        } catch (err: any) {
            console.error("Drop failed", err);
            addToast(err?.response?.data?.error || 'Operation failed', 'error');
        }
    };

    return (
        <div
            ref={containerRef}
            className="w-full h-full"
            onDragOver={handleDragOver}
            onDrop={handleDrop}
        >
            <Stage
                ref={stageRef}
                width={stageSize.width}
                height={stageSize.height}
                scaleX={zoom}
                scaleY={zoom}
                x={pan.x}
                y={pan.y}
                draggable={activeTool === 'pan'}
                onDragStart={handleDragStart}
                onDragEnd={(e) => {
                    handleDragEnd();
                    setPan({ x: e.target.x(), y: e.target.y() });
                }}
                onClick={handleStageClick}
                onWheel={handleWheel}
                style={{ cursor: activeTool === 'pan' ? 'grab' : 'default' }}
            >
                {/* Grid Layer */}
                <Layer>
                    {renderGrid()}
                </Layer>

                {/* Rooms Layer */}
                <Layer>
                    {rooms.map(room => (
                        <RoomShape
                            key={room.id}
                            room={room}
                            sections={sections.filter(s => s.roomId === room.id)} // Pass sections
                            isSelected={selectedIds.includes(room.id)}
                            selectedIds={selectedIds} // Pass all selectedIds for sections
                            isHovered={hoveredId === room.id}
                            onSelect={(id) => select([id])} // Generic select
                            onHover={(hover) => setHovered(hover ? room.id : null)}
                            onMove={(pos) => moveRoom(room.id, pos)}
                            onResize={(size) => resizeRoom(room.id, size)}
                        />
                    ))}

                    {/* Transformer for selected elements */}
                    <Transformer
                        ref={transformerRef}
                        boundBoxFunc={(oldBox, newBox) => {
                            // Limit minimum size
                            if (newBox.width < 50 || newBox.height < 50) {
                                return oldBox;
                            }
                            return newBox;
                        }}
                        rotateEnabled={false}
                        anchorCornerRadius={3}
                        anchorFill="#10b981"
                        anchorStroke="#10b981"
                        borderStroke="#10b981"
                    />
                </Layer>
            </Stage>
        </div>
    );
}

// Room Shape Component
function RoomShape({
    room,
    sections,
    isSelected,
    selectedIds,
    isHovered,
    onSelect,
    onHover,
    onMove,
    onResize,
}: {
    room: LayoutRoom;
    sections: import('../../../stores/layoutStore').LayoutSection[];
    isSelected: boolean;
    selectedIds: string[];
    isHovered: boolean;
    onSelect: (id: string) => void;
    onHover: (hover: boolean) => void;
    onMove: (pos: { x: number; y: number }) => void;
    onResize: (size: { width: number; height: number }) => void;
}) {
    const shapeRef = useRef<Konva.Group>(null);
    const color = room.color || ROOM_COLORS[room.type];

    return (
        <Group
            ref={shapeRef}
            id={`room-${room.id}`}
            x={room.position.x}
            y={room.position.y}
            draggable
            onClick={(e) => {
                e.cancelBubble = true;
                onSelect(room.id);
            }}
            onDragEnd={(e) => {
                onMove({ x: e.target.x(), y: e.target.y() });
            }}
            onTransformEnd={() => {
                const node = shapeRef.current;
                if (!node) return;

                const scaleX = node.scaleX();
                const scaleY = node.scaleY();

                // Reset scale and update size
                node.scaleX(1);
                node.scaleY(1);

                onResize({
                    width: Math.max(50, room.size.width * scaleX),
                    height: Math.max(50, room.size.height * scaleY),
                });
            }}
            onMouseEnter={() => onHover(true)}
            onMouseLeave={() => onHover(false)}
        >
            {/* Room Background */}
            <Rect
                width={room.size.width}
                height={room.size.height}
                fill={color}
                opacity={isSelected ? 0.4 : isHovered ? 0.35 : 0.25}
                cornerRadius={8}
            />

            {/* Room Border */}
            <Rect
                width={room.size.width}
                height={room.size.height}
                stroke={isSelected ? '#10b981' : color}
                strokeWidth={isSelected ? 3 : 2}
                cornerRadius={8}
            />

            {/* Sections */}
            {sections.map(section => (
                <SectionShape
                    key={section.id}
                    section={section}
                    isSelected={selectedIds.includes(section.id)}
                    onSelect={() => onSelect(section.id)}
                />
            ))}

            {/* Room Label */}
            <Text
                text={room.code}
                x={10}
                y={10}
                fill="white"
                fontSize={14}
                fontStyle="bold"
                fontFamily="Space Grotesk, sans-serif"
                listening={false}
            />

            {/* Room Name */}
            <Text
                text={room.name}
                x={10}
                y={28}
                fill="rgba(255,255,255,0.7)"
                fontSize={11}
                fontFamily="Space Grotesk, sans-serif"
                listening={false}
            />

            {/* Dimensions */}
            <Text
                text={`${Math.round(room.size.width / PIXELS_PER_FOOT)}' × ${Math.round(room.size.height / PIXELS_PER_FOOT)}'`}
                x={room.size.width - 60}
                y={room.size.height - 22}
                fill="rgba(255,255,255,0.5)"
                fontSize={10}
                fontFamily="JetBrains Mono, monospace"
                listening={false}
            />
        </Group>
    );
}

function SectionShape({
    section,
    isSelected,
    onSelect
}: {
    section: import('../../../stores/layoutStore').LayoutSection;
    isSelected: boolean;
    onSelect: () => void;
}) {
    const { updateSection, zoom, setSelectedPosition, selectedPosition } = useLayoutStore();

    // Section colors based on type
    const getColors = (type: string) => {
        switch (type) {
            case 'TABLE': return { fill: '#34d399', stroke: '#059669' }; // Emerald
            case 'RACK': return { fill: '#94a3b8', stroke: '#475569' }; // Slate
            case 'TRAY': return { fill: '#60a5fa', stroke: '#2563eb' }; // Blue
            default: return { fill: '#a78bfa', stroke: '#7c3aed' }; // Violet
        }
    };

    const colors = getColors(section.type);

    // Calculate cell dimensions
    const cellW = section.size.width / section.columns;
    const cellH = section.size.height / section.rows;
    // Show positions if zoomed in enough and data exists
    const showPositions = zoom > 0.6 && section.positions && section.positions.length > 0;

    // Color coding based on plant status/health/stage
    const getPositionColor = (pos: import('../../../stores/layoutStore').LayoutPosition): string => {
        if (pos.status === 'EMPTY') return 'rgba(255,255,255,0.4)';
        if (pos.status === 'RESERVED') return '#3b82f6'; // Blue
        if (pos.status === 'HARVESTED') return '#6b7280'; // Gray
        if (pos.status === 'ISSUE') return '#ef4444'; // Red

        // Planted - check health first
        if (pos.plant?.healthStatus === 'DEAD') return '#1f2937'; // Dark gray
        if (pos.plant?.healthStatus === 'SICK') return '#ef4444'; // Red
        if (pos.plant?.healthStatus === 'STRESSED') return '#f59e0b'; // Amber warning

        // Color by batch stage if available
        const stage = pos.plant?.batch?.stage?.toUpperCase() || '';
        if (stage.includes('FLOWER')) return '#a855f7'; // Purple
        if (stage.includes('VEG')) return '#22c55e'; // Green
        if (stage.includes('CLONE')) return '#3b82f6'; // Blue
        if (stage.includes('DRY')) return '#f59e0b'; // Amber
        if (stage.includes('CURE')) return '#f97316'; // Orange

        // Custom batch color if set
        if (pos.plant?.batch?.color) return pos.plant.batch.color;

        // Default planted color
        return '#22c55e'; // Green
    };

    const handlePositionClick = (pos: import('../../../stores/layoutStore').LayoutPosition, e: Konva.KonvaEventObject<MouseEvent>) => {
        e.cancelBubble = true;
        setSelectedPosition({
            ...pos,
            sectionName: section.name,
            roomName: section.code
        });
    };

    return (
        <Group
            id={`section-${section.id}`}
            x={section.position.x}
            y={section.position.y}
            draggable
            onClick={(e) => {
                e.cancelBubble = true;
                onSelect();
            }}
            onDragEnd={(e) => {
                updateSection(section.id, {
                    position: { x: e.target.x(), y: e.target.y() }
                });
            }}
        >
            <Rect
                width={section.size.width}
                height={section.size.height}
                fill={colors.fill}
                stroke={isSelected ? '#white' : colors.stroke}
                strokeWidth={isSelected ? 2 : 1}
                opacity={0.8}
                cornerRadius={2}
            />

            {/* Render Positions (LOD) */}
            {showPositions ? (
                section.positions?.map(pos => {
                    const px = (pos.column - 1) * cellW;
                    const py = (pos.row - 1) * cellH;
                    const padding = Math.min(2, cellW * 0.1);
                    const isPositionSelected = selectedPosition?.id === pos.id;

                    return (
                        <Rect
                            key={pos.id}
                            x={px + padding}
                            y={py + padding}
                            width={cellW - padding * 2}
                            height={cellH - padding * 2}
                            fill={getPositionColor(pos)}
                            stroke={isPositionSelected ? '#fbbf24' : 'rgba(0,0,0,0.1)'}
                            strokeWidth={isPositionSelected ? 2 : 0.5}
                            cornerRadius={mapNodeTypeToRadius(section.type)}
                            onClick={(e) => handlePositionClick(pos, e)}
                            onMouseEnter={(e) => {
                                const container = e.target.getStage()?.container();
                                if (container) container.style.cursor = pos.status === 'PLANTED' ? 'pointer' : 'crosshair';
                            }}
                            onMouseLeave={(e) => {
                                const container = e.target.getStage()?.container();
                                if (container) container.style.cursor = 'default';
                            }}
                        />
                    );
                })
            ) : (
                <>
                    {/* Fallback Grid Lines */}
                    {section.rows > 1 && (
                        Array.from({ length: section.rows - 1 }).map((_, i) => (
                            <Line
                                key={`r-${i}`}
                                points={[0, (i + 1) * cellH, section.size.width, (i + 1) * cellH]}
                                stroke="rgba(0,0,0,0.1)"
                                strokeWidth={1}
                                listening={false}
                            />
                        ))
                    )}
                    {section.columns > 1 && (
                        Array.from({ length: section.columns - 1 }).map((_, i) => (
                            <Line
                                key={`c-${i}`}
                                points={[(i + 1) * cellW, 0, (i + 1) * cellW, section.size.height]}
                                stroke="rgba(0,0,0,0.1)"
                                strokeWidth={1}
                                listening={false}
                            />
                        ))
                    )}
                </>
            )}

            <Text
                text={section.code}
                width={section.size.width}
                align="center"
                y={showPositions ? -15 : section.size.height / 2 - 5}
                fontSize={10}
                fill={showPositions ? 'white' : "rgba(0,0,0,0.6)"}
                fontStyle="bold"
                listening={false}
            />
        </Group>
    );
}

function mapNodeTypeToRadius(type: string): number {
    return type === 'TRAY' ? 10 : 2; // Circlish for trays
}
