import { useEffect, useState } from 'react';
import { useMapEvents, Polyline, Marker } from 'react-leaflet';
import L from 'leaflet';
import { useDrawingStore } from '../../stores/drawingStore';
import { useUIStore } from '../../stores/uiStore';
import { mapItemService } from '../../services/mapItemService';
import { CABLE_COLORS, type CableType } from '../../types/mapItem';

interface DrawingHandlerProps {
  mapId: string;
  onItemCreated: () => void;
}

export function DrawingHandler({ mapId, onItemCreated }: DrawingHandlerProps) {
  const { activeTool, isDrawing, drawingPoints, setIsDrawing, addDrawingPoint, resetDrawing, setActiveTool } =
    useDrawingStore();
  const { showToast } = useUIStore();
  const [cursorPosition, setCursorPosition] = useState<[number, number] | null>(null);
  const [allItems, setAllItems] = useState<any[]>([]);
  const [startDeviceId, setStartDeviceId] = useState<string | null>(null);
  const [endDeviceId, setEndDeviceId] = useState<string | null>(null);

  const isCableTool = ['fiber', 'cat6', 'cat6_poe'].includes(activeTool);
  const isDeviceTool = ['switch', 'indoor_ap', 'outdoor_ap'].includes(activeTool);
  const isWirelessTool = activeTool === 'wireless_mesh';

  // Load all map items for snapping
  useEffect(() => {
    const loadItems = async () => {
      try {
        const items = await mapItemService.getMapItems(mapId);
        setAllItems(items);
      } catch (error) {
        console.error('Failed to load items for snapping:', error);
      }
    };
    loadItems();
  }, [mapId]);

  // Find nearby device for snapping
  const findNearbyDevice = (lat: number, lng: number, radiusMeters = 5): any | null => {
    const devices = allItems.filter(item =>
      ['switch', 'indoor_ap', 'outdoor_ap'].includes(item.type) &&
      item.geometry.type === 'Point'
    );

    for (const device of devices) {
      const [deviceLng, deviceLat] = device.geometry.coordinates;
      const distance = map.distance([lat, lng], [deviceLat, deviceLng]);

      if (distance <= radiusMeters) {
        return device;
      }
    }

    return null;
  };

  // Check if device has available ports
  const hasAvailablePorts = (device: any): boolean => {
    const portCount = device.properties.port_count || 0;
    const usedPorts = device.properties.connections?.length || 0;
    return usedPorts < portCount;
  };

  // Count wireless mesh connections for an AP
  const getWirelessMeshCount = (apId: string): number => {
    const meshLinks = allItems.filter(item =>
      item.type === 'wireless_mesh' &&
      (item.properties.start_ap_id === apId || item.properties.end_ap_id === apId)
    );
    return meshLinks.length;
  };

  const map = useMapEvents({
    click: async (e) => {
      if (activeTool === 'select') return;

      let { lat, lng } = e.latlng;
      let clickedDevice = null;

      // Check for nearby device when drawing cables
      if (isCableTool && map) {
        clickedDevice = findNearbyDevice(lat, lng);
        if (clickedDevice) {
          // Check if device has available ports
          if (!hasAvailablePorts(clickedDevice)) {
            const portCount = clickedDevice.properties.port_count || 0;
            const usedPorts = clickedDevice.properties.connections?.length || 0;
            const deviceName = clickedDevice.properties.name || clickedDevice.type;
            showToast(`${deviceName} has no available ports (${usedPorts}/${portCount} ports used). Please select a different device or increase the port count.`, 'error');
            return;
          }

          // Snap to device center
          const [deviceLng, deviceLat] = clickedDevice.geometry.coordinates;
          lat = deviceLat;
          lng = deviceLng;

          // Track device connection
          if (!isDrawing) {
            setStartDeviceId(clickedDevice.id);
          } else {
            setEndDeviceId(clickedDevice.id);
          }
        }
      }

      // Device placement - single click
      if (isDeviceTool) {
        try {
          await mapItemService.createMapItem(mapId, {
            type: activeTool as any,
            geometry: {
              type: 'Point',
              coordinates: [lng, lat],
            },
            properties: {
              name: `${activeTool} at ${lat.toFixed(4)}, ${lng.toFixed(4)}`,
              port_count: activeTool === 'switch' ? 5 : activeTool === 'outdoor_ap' ? 1 : 4,
              connections: [],
            },
          });
          onItemCreated();
          // Reload items for snapping
          const items = await mapItemService.getMapItems(mapId);
          setAllItems(items);
        } catch (error) {
          console.error('Failed to create device:', error);
        }
        return;
      }

      // Cable drawing - multi-point
      if (isCableTool) {
        if (!isDrawing) {
          setIsDrawing(true);
          addDrawingPoint([lat, lng]);
        } else {
          addDrawingPoint([lat, lng]);
        }
      }

      // Wireless mesh - connect AP to AP only
      if (isWirelessTool) {
        // Must click on an AP
        const ap = findNearbyDevice(lat, lng, 5);
        if (!ap || !['indoor_ap', 'outdoor_ap'].includes(ap.type)) {
          showToast('Wireless mesh can only connect between Access Points. Please click on an AP.', 'error');
          return;
        }

        // Check wireless mesh connection limit (max 4 per AP)
        const meshCount = getWirelessMeshCount(ap.id);
        if (meshCount >= 4) {
          const apName = ap.properties.name || ap.type;
          showToast(`${apName} already has the maximum of 4 wireless mesh connections. Please select a different AP.`, 'error');
          return;
        }

        if (!isDrawing) {
          // First AP clicked
          setIsDrawing(true);
          setStartDeviceId(ap.id);
          const [apLng, apLat] = ap.geometry.coordinates;
          addDrawingPoint([apLat, apLng]);
        } else if (drawingPoints.length === 1) {
          // Second AP clicked - check if it's different from first
          if (ap.id === startDeviceId) {
            showToast('Cannot create wireless mesh to the same Access Point. Please select a different AP.', 'error');
            return;
          }

          // Second AP clicked - finish immediately with both points
          const [apLng, apLat] = ap.geometry.coordinates;
          const secondPoint: [number, number] = [apLat, apLng];
          await finishWirelessMesh(ap.id, secondPoint);
        }
      }
    },

    mousemove: (e) => {
      // Update cursor position for preview line
      if (isDrawing && (isCableTool || isWirelessTool)) {
        setCursorPosition([e.latlng.lat, e.latlng.lng]);
      }
    },

    contextmenu: async (e) => {
      // Right-click to finish cable drawing
      if (isCableTool && isDrawing && drawingPoints.length >= 2) {
        e.originalEvent.preventDefault();
        e.originalEvent.stopPropagation();
        await finishCable();
        return false;
      }

      if (!isDrawing) {
        e.originalEvent.preventDefault();
      }
    },
  });

  useEffect(() => {
    // Listen for Escape key globally
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape' && isDrawing) {
        resetDrawing();
        setCursorPosition(null);
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [isDrawing, resetDrawing]);

  const finishCable = async () => {
    if (drawingPoints.length < 2) return;

    try {
      const cableType = activeTool as CableType;
      await mapItemService.createMapItem(mapId, {
        type: 'cable',
        geometry: {
          type: 'LineString',
          coordinates: drawingPoints.map(([lat, lng]) => [lng, lat]),
        },
        properties: {
          cable_type: cableType,
          name: `${cableType} cable`,
          start_device_id: startDeviceId,
          end_device_id: endDeviceId,
        },
      });
      onItemCreated();
      resetDrawing();
      setCursorPosition(null);
      setStartDeviceId(null);
      setEndDeviceId(null);
      // Reload items
      const items = await mapItemService.getMapItems(mapId);
      setAllItems(items);
    } catch (error) {
      console.error('Failed to create cable:', error);
    }
  };

  const finishWirelessMesh = async (endApId: string, secondPoint: [number, number]) => {
    if (drawingPoints.length !== 1) {
      console.error('Wireless mesh requires exactly 1 starting point');
      return;
    }

    try {
      // Create line with first point from state and second point from parameter
      const coordinates = [
        [drawingPoints[0][1], drawingPoints[0][0]], // First point: [lng, lat]
        [secondPoint[1], secondPoint[0]], // Second point: [lng, lat]
      ];

      await mapItemService.createMapItem(mapId, {
        type: 'wireless_mesh',
        geometry: {
          type: 'LineString',
          coordinates: coordinates,
        },
        properties: {
          name: 'Wireless mesh link',
          start_ap_id: startDeviceId,
          end_ap_id: endApId,
        },
      });
      onItemCreated();
      // Reset drawing state but keep the wireless mesh tool active
      resetDrawing();
      setCursorPosition(null);
      setStartDeviceId(null);
      setEndDeviceId(null);
      // Reload items
      const items = await mapItemService.getMapItems(mapId);
      setAllItems(items);
    } catch (error) {
      console.error('Failed to create wireless mesh:', error);
      // Reset on error too
      resetDrawing();
      setCursorPosition(null);
      setStartDeviceId(null);
      setEndDeviceId(null);
    }
  };

  // Render drawing preview
  if (isDrawing && drawingPoints.length > 0) {
    const color = isCableTool
      ? CABLE_COLORS[activeTool as CableType]
      : isWirelessTool
      ? '#10B981'
      : '#6B7280';

    const dashArray = isWirelessTool ? '10, 10' : undefined;

    // Create preview line from last point to cursor
    const previewPositions = cursorPosition
      ? [...drawingPoints, cursorPosition]
      : drawingPoints;

    return (
      <>
        {/* Main line connecting all points */}
        {drawingPoints.length > 1 && (
          <Polyline
            positions={drawingPoints}
            color={color}
            weight={3}
            dashArray={dashArray}
            opacity={0.8}
          />
        )}

        {/* Preview line from last point to cursor */}
        {cursorPosition && drawingPoints.length > 0 && (
          <Polyline
            positions={[drawingPoints[drawingPoints.length - 1], cursorPosition]}
            color={color}
            weight={3}
            dashArray="5, 5"
            opacity={0.5}
          />
        )}

        {/* Markers at each point */}
        {drawingPoints.map((point, idx) => (
          <Marker key={idx} position={point} />
        ))}
      </>
    );
  }

  return null;
}
