import { useRef, useCallback } from 'react';
import { MapContainer, TileLayer, useMapEvents, useMap } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import type { Map as LeafletMap } from 'leaflet';
import type { Site } from '@/types/index.ts';
import { useSitesStore } from '@/store/sites.ts';
import { useSettingsStore } from '@/store/settings.ts';
import { useToastStore } from '@/components/ui/Toast.tsx';
import SiteMarker from './SiteMarker.tsx';
import MapExtras from './MapExtras.tsx';
import CoordinateGrid from './CoordinateGrid.tsx';
import MeasurementTool from './MeasurementTool.tsx';
import ElevationDisplay from './ElevationDisplay.tsx';

interface MapViewProps {
  onMapClick: (lat: number, lon: number) => void;
  onEditSite: (site: Site) => void;
  children?: React.ReactNode;
}

function MapClickHandler({
  onMapClick,
}: {
  onMapClick: (lat: number, lon: number) => void;
}) {
  const isPlacingMode = useSitesStore((s) => s.isPlacingMode);

  useMapEvents({
    click: (e) => {
      if (isPlacingMode) {
        onMapClick(e.latlng.lat, e.latlng.lng);
      }
    },
  });

  return null;
}

/**
 * Inner component that exposes the map instance via ref callback
 */
function MapRefSetter({ mapRef }: { mapRef: React.MutableRefObject<LeafletMap | null> }) {
  const map = useMap();
  mapRef.current = map;
  return null;
}

export default function MapView({ onMapClick, onEditSite, children }: MapViewProps) {
  const sites = useSitesStore((s) => s.sites);
  const isPlacingMode = useSitesStore((s) => s.isPlacingMode);
  const showTerrain = useSettingsStore((s) => s.showTerrain);
  const terrainOpacity = useSettingsStore((s) => s.terrainOpacity);
  const setShowTerrain = useSettingsStore((s) => s.setShowTerrain);
  const showGrid = useSettingsStore((s) => s.showGrid);
  const setShowGrid = useSettingsStore((s) => s.setShowGrid);
  const measurementMode = useSettingsStore((s) => s.measurementMode);
  const setMeasurementMode = useSettingsStore((s) => s.setMeasurementMode);
  const showElevationInfo = useSettingsStore((s) => s.showElevationInfo);
  const showElevationOverlay = useSettingsStore((s) => s.showElevationOverlay);
  const setShowElevationOverlay = useSettingsStore((s) => s.setShowElevationOverlay);
  const addToast = useToastStore((s) => s.addToast);
  const mapRef = useRef<LeafletMap | null>(null);

  const handleFitToSites = useCallback(() => {
    if (sites.length === 0 || !mapRef.current) return;
    const bounds = sites.map((site) => [site.lat, site.lon] as [number, number]);
    mapRef.current.fitBounds(bounds, { padding: [50, 50] });
  }, [sites]);

  const handleResetView = useCallback(() => {
    mapRef.current?.setView([48.4, 35.0], 7);
  }, []);

  return (
    <>
      <MapContainer
        center={[48.4, 35.0]}
        zoom={7}
        className={`w-full h-full ${isPlacingMode ? 'cursor-crosshair' : ''}`}
      >
        <MapRefSetter mapRef={mapRef} />
        {/* Base OSM layer */}
        <TileLayer
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        {/* Terrain overlay (OpenTopoMap, above base map, below heatmap) */}
        {showTerrain && (
          <TileLayer
            attribution='Map data: &copy; OpenStreetMap, SRTM | Style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a>'
            url="https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png"
            opacity={terrainOpacity}
            zIndex={100}
          />
        )}
        {/* Elevation color overlay (Stamen Terrain via Stadia Maps) */}
        {showElevationOverlay && (
          <TileLayer
            attribution='&copy; Stamen Design'
            url="https://tiles.stadiamaps.com/tiles/stamen_terrain/{z}/{x}/{y}.png"
            opacity={0.5}
            zIndex={97}
          />
        )}
        <MapClickHandler onMapClick={onMapClick} />
        <MapExtras />
        {showElevationInfo && <ElevationDisplay />}
        <CoordinateGrid visible={showGrid} />
        <MeasurementTool
          enabled={measurementMode}
          onComplete={(distKm) => {
            addToast(`Distance: ${distKm.toFixed(2)} km (${(distKm * 1000).toFixed(0)} m)`, 'info');
            setMeasurementMode(false);
          }}
        />
        {sites
          .filter((s) => s.visible)
          .map((site) => (
            <SiteMarker key={site.id} site={site} onEdit={onEditSite} />
          ))}
        {children}
      </MapContainer>

      {/* Map control buttons */}
      <div className="absolute top-4 right-4 z-[1000] flex flex-col gap-2">
        <button
          onClick={handleFitToSites}
          disabled={sites.length === 0}
          className="bg-white dark:bg-dark-surface shadow-lg rounded px-3 py-2 text-sm
            hover:bg-gray-50 dark:hover:bg-dark-border transition-colors
            disabled:opacity-40 disabled:cursor-not-allowed
            text-gray-700 dark:text-dark-text min-h-[36px]"
          title="Fit view to all sites"
        >
          Fit
        </button>
        <button
          onClick={handleResetView}
          className="bg-white dark:bg-dark-surface shadow-lg rounded px-3 py-2 text-sm
            hover:bg-gray-50 dark:hover:bg-dark-border transition-colors
            text-gray-700 dark:text-dark-text min-h-[36px]"
          title="Reset to Ukraine view"
        >
          Reset
        </button>
        <button
          onClick={() => setShowTerrain(!showTerrain)}
          className={`bg-white dark:bg-dark-surface shadow-lg rounded px-3 py-2 text-sm
            hover:bg-gray-50 dark:hover:bg-dark-border transition-colors
            text-gray-700 dark:text-dark-text min-h-[36px]
            ${showTerrain ? 'ring-2 ring-blue-500' : ''}`}
          title={showTerrain ? 'Hide terrain' : 'Show terrain elevation'}
        >
          Topo
        </button>
        <button
          onClick={() => setShowGrid(!showGrid)}
          className={`bg-white dark:bg-dark-surface shadow-lg rounded px-3 py-2 text-sm
            hover:bg-gray-50 dark:hover:bg-dark-border transition-colors
            text-gray-700 dark:text-dark-text min-h-[36px]
            ${showGrid ? 'ring-2 ring-green-500' : ''}`}
          title={showGrid ? 'Hide coordinate grid' : 'Show coordinate grid'}
        >
          Grid
        </button>
        <button
          onClick={() => setMeasurementMode(!measurementMode)}
          className={`bg-white dark:bg-dark-surface shadow-lg rounded px-3 py-2 text-sm
            hover:bg-gray-50 dark:hover:bg-dark-border transition-colors
            text-gray-700 dark:text-dark-text min-h-[36px]
            ${measurementMode ? 'ring-2 ring-orange-500' : ''}`}
          title={measurementMode ? 'Exit measurement mode' : 'Measure distance (click points, right-click to finish)'}
        >
          Ruler
        </button>
        <button
          onClick={() => setShowElevationOverlay(!showElevationOverlay)}
          className={`bg-white dark:bg-dark-surface shadow-lg rounded px-3 py-2 text-sm
            hover:bg-gray-50 dark:hover:bg-dark-border transition-colors
            text-gray-700 dark:text-dark-text min-h-[36px]
            ${showElevationOverlay ? 'ring-2 ring-amber-500' : ''}`}
          title={showElevationOverlay ? 'Hide elevation colors' : 'Show elevation color overlay'}
        >
          Elev
        </button>
      </div>
    </>
  );
}
