import React, { useState, useRef, useCallback, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { MapNode } from '@/components/MapNode';
import { SystemContextMenu } from '@/components/SystemContextMenu';
import { Connection } from '@/components/Connection';
import { useRegionData } from '@/hooks/useRegionData';
import { loadWormholeSystems, saveWormholeSystem, deleteWormholeSystem } from '@/utils/wormholeStorage';
import { System, Position, Connection as ConnectionType } from '@/lib/types';
import { getSecurityColor } from '@/utils/securityColors';
import { Header } from './Header';

interface RegionMapProps {
  regionName: string;
  focusSystem?: string;
  isCompact?: boolean;
  isWormholeRegion?: boolean;
}

interface ContextMenuState {
  x: number,
  y: number,
  system: System
}

function computeNodePositions(systems: Map<string, System>): Record<string, Position> {
  const nodePositions: Record<string, Position> = {};
  systems.forEach((system, key) => {
    nodePositions[key] = { x: system.x, y: system.y };
  });
  return nodePositions;
}
function computeNodeConnections(systems: Map<string, System>): Map<string, ConnectionType> {
  const connections: Map<string, ConnectionType> = new Map();
  for (const [key, system] of systems.entries()) {
    const connectedSystems = system.connectedSystems.split(',');
    for (let connectedSystem of connectedSystems) {
      connectedSystem = connectedSystem.trim();
      const connectionKey = [key, connectedSystem].sort().join('-');
      const destinationSystem = systems.get(connectedSystem);
      if (destinationSystem) {
        const averageSecurity = ((system.security || 0) + (destinationSystem.security || 0)) / 2;
        const connection = {
          key: connectionKey,
          from: { x: system.x, y: system.y },
          to: { x: destinationSystem.x, y: destinationSystem.y },
          color: getSecurityColor(averageSecurity)
        }
        connections.set(connectionKey, connection);
      } else {
        console.log(`Destination system ${connectedSystem} not found for ${key}`);
      }
    }
  }
  return connections;
}

export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormholeRegion = false }: RegionMapProps) => {
  const navigate = useNavigate();
  const [viewBox, setViewBox] = useState({ x: 0, y: 0, width: 1200, height: 800 });
  const [isPanning, setIsPanning] = useState(false);
  const [lastPanPoint, setLastPanPoint] = useState({ x: 0, y: 0 });
  const [draggingNode, setDraggingNode] = useState<string | null>(null);
  const [tempConnection, setTempConnection] = useState<{ from: Position; to: Position } | null>(null);
  const [systems, setSystems] = useState<Map<string, System>>(new Map());
  const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
  const [connections, setConnections] = useState<Map<string, ConnectionType>>(new Map());
  const [positions, setPositions] = useState<Record<string, Position>>({});
  const svgRef = useRef<SVGSVGElement>(null);

  const { data: rsystems, isLoading, error } = useRegionData(regionName);
  useEffect(() => {
    if (!isLoading && error == null && rsystems && rsystems.size > 0)
      setSystems(rsystems);
  }, [rsystems, isLoading, error]);

  // Process connections when systems or nodePositions change
  useEffect(() => {
    if (!systems || systems.size === 0) return;
    console.log("Computing node positions");
    const positions = computeNodePositions(systems);
    setPositions(positions);
    console.log("Computing node connections");
    const connections = computeNodeConnections(systems);
    setConnections(connections);
  }, [systems]);

  // Load wormhole systems on mount if in wormhole region
  useEffect(() => {
    if (isWormholeRegion) {
      loadWormholeSystems().then(wormholeSystems => {
        setSystems(wormholeSystems);
      });
    }
  }, [isWormholeRegion]);

  const handleSystemClick = (systemName: string) => {
    if (focusSystem === systemName) return;
    navigate(`/regions/${regionName}/${systemName}`);
  };

  const handleSystemDoubleClick = async (e: React.MouseEvent, position: Position) => {
    if (!isWormholeRegion) return;
    e.stopPropagation();

    // Create a new system at the clicked position
    const newSystemName = `WH-${Date.now()}`;
    const newSystem: System = {
      solarSystemName: newSystemName,
      x: position.x,
      y: position.y,
      connectedSystems: ''
    }
    const dbSystem = await saveWormholeSystem(newSystem);
    setSystems(new Map(systems).set(newSystemName, dbSystem));
  };

  const handleMapDoubleClick = (e: React.MouseEvent) => {
    if (!isWormholeRegion || !svgRef.current) return;
    e.stopPropagation();

    const point = svgRef.current.createSVGPoint();
    point.x = e.clientX;
    point.y = e.clientY;

    // Convert to SVG coordinates
    const svgPoint = point.matrixTransform(svgRef.current.getScreenCTM()!.inverse());
    const x = svgPoint.x;
    const y = svgPoint.y;

    handleSystemDoubleClick(e, { x, y });
  };

  const handleNodeDragStart = (e: React.MouseEvent, nodeId: string) => {
    if (!isWormholeRegion) return;
    e.stopPropagation();
    setDraggingNode(nodeId);

    const point = svgRef.current.createSVGPoint();
    point.x = e.clientX;
    point.y = e.clientY;

    // Convert to SVG coordinates
    const svgPoint = point.matrixTransform(svgRef.current.getScreenCTM()!.inverse());
    const x = svgPoint.x;
    const y = svgPoint.y;

    setTempConnection({
      from: { x: systems.get(nodeId)!.x, y: systems.get(nodeId)!.y },
      to: { x, y }
    });
  };

  const handleSvgMouseMove = (e: React.MouseEvent) => {
    if (!draggingNode || !isWormholeRegion || !svgRef.current) return;
    e.stopPropagation();

    // Create a point in screen coordinates
    const point = svgRef.current.createSVGPoint();
    point.x = e.clientX;
    point.y = e.clientY;

    // Convert to SVG coordinates
    const svgPoint = point.matrixTransform(svgRef.current.getScreenCTM()!.inverse());
    const x = svgPoint.x;
    const y = svgPoint.y;

    // Check for nearby systems to snap to
    var targetSystem: System | null = null;
    systems.forEach(system => {
      if (system.solarSystemName === draggingNode) return;
      const dx = system.x - x;
      const dy = system.y - y;
      const distance = Math.sqrt(dx * dx + dy * dy);
      if (distance < 20) {
        targetSystem = system;
      }
    });

    // Update temp connection with either snapped position or exact mouse position
    setTempConnection(prev => prev ? {
      from: prev.from,
      to: targetSystem ? { x: targetSystem.x, y: targetSystem.y } : { x, y }
    } : null);

    if (targetSystem)
      handleNodeDragEnd(e, targetSystem.solarSystemName);
  };

  const handleSvgMouseUp = (e: React.MouseEvent) => {
    if (!draggingNode || !isWormholeRegion) return;
    e.stopPropagation();
    handleNodeDragEnd(e);
  };

  const handleNodeDragEnd = (e: React.MouseEvent, targetNodeId?: string) => {
    if (!draggingNode || !isWormholeRegion) return;
    e.stopPropagation();

    if (targetNodeId && targetNodeId !== draggingNode) {
      // Check if connection already exists
      const connectionKey = [draggingNode, targetNodeId].sort().join('-');
      const connectionExists = connections.has(connectionKey);

      if (!connectionExists) {
        const systemFrom = systems.get(draggingNode)!;
        const systemTo = systems.get(targetNodeId)!;

        const systemFromConnectedSystems = systemFrom.connectedSystems.split(",").filter(system => system != "");
        systemFromConnectedSystems.push(targetNodeId);
        systemFrom.connectedSystems = systemFromConnectedSystems.join(",");

        const systemToConnectedSystems = systemTo.connectedSystems.split(",").filter(system => system != "");
        systemToConnectedSystems.push(draggingNode);
        systemTo.connectedSystems = systemToConnectedSystems.join(",");

        systems.set(draggingNode, systemFrom);
        systems.set(targetNodeId, systemTo);
        setSystems(new Map(systems));

        // We will just trust that they got saved
        saveWormholeSystem(systemFrom);
        saveWormholeSystem(systemTo);
      }
    }

    setDraggingNode(null);
    setTempConnection(null);
  };

  const handleMouseDown = useCallback((e: React.MouseEvent) => {
    if (!svgRef.current) return;
    setIsPanning(true);
    const rect = svgRef.current.getBoundingClientRect();
    setLastPanPoint({
      x: e.clientX - rect.left,
      y: e.clientY - rect.top
    });
  }, []);

  const handleMouseMove = useCallback((e: React.MouseEvent) => {
    if (!isPanning || !svgRef.current) return;

    const rect = svgRef.current.getBoundingClientRect();
    const currentPoint = {
      x: e.clientX - rect.left,
      y: e.clientY - rect.top
    };

    const deltaX = (lastPanPoint.x - currentPoint.x) * (viewBox.width / rect.width);
    const deltaY = (lastPanPoint.y - currentPoint.y) * (viewBox.height / rect.height);

    setViewBox(prev => ({
      ...prev,
      x: prev.x + deltaX,
      y: prev.y + deltaY
    }));

    setLastPanPoint(currentPoint);
  }, [isPanning, lastPanPoint, viewBox.width, viewBox.height]);

  const handleMouseUp = useCallback(() => {
    setIsPanning(false);
  }, []);

  const handleWheel = useCallback((e: React.WheelEvent) => {
    e.preventDefault();
    if (!svgRef.current) return;

    const rect = svgRef.current.getBoundingClientRect();
    const mouseX = e.clientX - rect.left;
    const mouseY = e.clientY - rect.top;

    const scale = e.deltaY < 0 ? 1.1 : 0.9;
    const newWidth = viewBox.width * scale;
    const newHeight = viewBox.height * scale;

    const mouseXInSVG = viewBox.x + (mouseX / rect.width) * viewBox.width;
    const mouseYInSVG = viewBox.y + (mouseY / rect.height) * viewBox.height;

    const newX = mouseXInSVG - (mouseX / rect.width) * newWidth;
    const newY = mouseYInSVG - (mouseY / rect.height) * newHeight;

    setViewBox({
      x: newX,
      y: newY,
      width: newWidth,
      height: newHeight
    });
  }, [viewBox]);

  const handleContextMenu = (e: React.MouseEvent, system: System) => {
    if (!isWormholeRegion) return;
    e.preventDefault();
    e.stopPropagation();

    const rect = svgRef.current?.getBoundingClientRect();
    if (!rect) return;

    setContextMenu({
      x: e.clientX,
      y: e.clientY,
      system: system
    });
  };

  const handleRenameSystem = (oldName: string, newName: string) => {
    const system = systems.get(oldName);
    if (system) {
      const newSystems = new Map(systems);
      system.solarSystemName = newName;
      newSystems.set(newName, system);
      newSystems.delete(oldName);
      saveWormholeSystem(system);

      // Update all the systems this system connects to
      const connectedSystems = system.connectedSystems.split(',');
      for (const connectedSystem of connectedSystems) {
        const connectedSystemobj = newSystems.get(connectedSystem);
        if (connectedSystemobj) {
          connectedSystemobj.connectedSystems = connectedSystemobj.connectedSystems.replace(oldName, newName);
          newSystems.set(connectedSystem, connectedSystemobj);
          saveWormholeSystem(connectedSystemobj);
        }
      }

      // Update all the systems that connect to this system
      for (const [key, system] of newSystems.entries()) {
        if (system.connectedSystems.includes(oldName)) {
          system.connectedSystems = system.connectedSystems.replace(oldName, newName);
          newSystems.set(key, system);
          saveWormholeSystem(system);
        }
      }

      setSystems(newSystems);
    }

    setContextMenu(null);
  };

  const handleClearConnections = async (system: System) => {
    system.connectedSystems = '';
    for (const [key, isystem] of systems.entries()) {
      if (system.solarSystemName === isystem.solarSystemName) continue;
      if (!isystem.connectedSystems.includes(system.solarSystemName)) continue;
      isystem.connectedSystems = isystem.connectedSystems.split(',').filter(connectedSystem => connectedSystem !== system.solarSystemName).join(',');
      systems.set(key, isystem);
      saveWormholeSystem(isystem);
    }
    setSystems(new Map(systems));
    saveWormholeSystem(system);
    setContextMenu(null);
  };

  const handleDeleteSystem = async (system: System) => {
    try {
      const newSystems = new Map(systems);
      newSystems.delete(system.solarSystemName);
      setSystems(newSystems);
      await deleteWormholeSystem(system);
      setContextMenu(null);
    } catch (error) {
      console.error('Error deleting system:', error);
    }
  };

  // Close context menu when clicking outside
  useEffect(() => {
    const handleClickOutside = () => setContextMenu(null);
    document.addEventListener('click', handleClickOutside);
    return () => document.removeEventListener('click', handleClickOutside);
  }, []);

  if (isLoading) {
    return (
      <div className="h-full w-full bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 flex items-center justify-center">
        <div className="text-white text-xl">Loading {regionName} data...</div>
      </div>
    );
  }

  if (error) {
    return (
      <div className="h-full w-full bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 flex items-center justify-center">
        <div className="text-center">
          <h1 className="text-4xl font-bold text-white mb-4">Error Loading Region</h1>
          <p className="text-red-400 mb-6">Failed to load data for {regionName}</p>
        </div>
      </div>
    );
  }

  return (
    <div className="w-full h-full bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 relative">
      <Header
        title={`Region: ${regionName}`}
        breadcrumbs={[
          { label: "Universe", path: "/" },
          { label: regionName }
        ]}
      />
      <svg
        ref={svgRef}
        width="100%"
        height="100%"
        viewBox={`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`}
        className="cursor-grab active:cursor-grabbing"
        onMouseDown={handleMouseDown}
        onMouseMove={(e) => {
          if (isPanning) {
            handleMouseMove(e);
          } else {
            handleSvgMouseMove(e);
          }
        }}
        onMouseUp={(e) => {
          if (isPanning) {
            handleMouseUp();
          } else {
            handleSvgMouseUp(e);
          }
        }}
        onMouseLeave={handleMouseUp}
        onWheel={handleWheel}
        onDoubleClick={handleMapDoubleClick}
      >
        <defs>
          <filter id="glow">
            <feGaussianBlur stdDeviation="3" result="coloredBlur" />
            <feMerge>
              <feMergeNode in="coloredBlur" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>
        </defs>

        {/* Render all connections */}
        {Array.from(connections.entries()).map(([key, connection]) => (
          <Connection
            key={key}
            from={connection.from}
            to={connection.to}
            color={connection.color}
          />
        ))}

        {/* Render temporary connection while dragging */}
        {tempConnection && (
          <Connection
            from={tempConnection.from}
            to={tempConnection.to}
            color="#f472b6"
          />
        )}

        {/* Render existing systems */}
        {Array.from(systems.entries()).map(([key, system]) => (
          <MapNode
            key={key}
            id={system.solarSystemName}
            name={system.solarSystemName}
            position={positions[system.solarSystemName] || { x: 0, y: 0 }}
            onClick={() => handleSystemClick(system.solarSystemName)}
            onDoubleClick={(e) => handleSystemDoubleClick(e, positions[system.solarSystemName])}
            onDragStart={(e) => handleNodeDragStart(e, system.solarSystemName)}
            onDrag={handleSvgMouseMove}
            onDragEnd={handleNodeDragEnd}
            onContextMenu={(e) => handleContextMenu(e, system)}
            type="system"
            security={system.security}
            signatures={system.signatures}
            isDraggable={isWormholeRegion}
          />
        ))}

        {/* Highlight focused system */}
        {focusSystem && positions[focusSystem] && (
          <circle
            cx={positions[focusSystem].x}
            cy={positions[focusSystem].y}
            r="15"
            fill="none"
            stroke="#a855f7"
            strokeWidth="3"
            strokeDasharray="5,5"
            opacity="0.8"
          >
            <animateTransform
              attributeName="transform"
              attributeType="XML"
              type="rotate"
              from={`0 ${positions[focusSystem].x} ${positions[focusSystem].y}`}
              to={`360 ${positions[focusSystem].x} ${positions[focusSystem].y}`}
              dur="10s"
              repeatCount="indefinite"
            />
          </circle>
        )}
      </svg>

      {/* Context Menu */}
      {contextMenu && (
        <SystemContextMenu
          x={contextMenu.x}
          y={contextMenu.y}
          system={systems.get(contextMenu.system.solarSystemName)!}
          onRename={(newName) => handleRenameSystem(contextMenu.system.solarSystemName, newName)}
          onDelete={handleDeleteSystem}
          onClearConnections={handleClearConnections}
          onClose={() => setContextMenu(null)}
        />
      )}
    </div>
  );
};
