// src/features/legislativas/nacionales/components/MapaNacional.tsx
import axios from 'axios';
import { Suspense, useState, useEffect, useCallback, useRef } from 'react';
import { useSuspenseQuery } from '@tanstack/react-query';
import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps';
import { Tooltip } from 'react-tooltip';
import { geoCentroid } from 'd3-geo';
import { feature } from 'topojson-client';
import { API_BASE_URL, assetBaseUrl } from '../../../../apiService';
import type { ResultadoMapaDto, AmbitoGeography } from '../../../../types/types';
import { MapaProvincial } from './MapaProvincial';
import { CabaLupa } from './CabaLupa';
import { BiZoomIn, BiZoomOut } from "react-icons/bi";
import toast from 'react-hot-toast';
import { useMediaQuery } from '../hooks/useMediaQuery';
// 1. Importamos el archivo de estilos como un módulo CSS
import styles from '../PanelNacional.module.css';

const DEFAULT_MAP_COLOR = '#E0E0E0';
const FADED_BACKGROUND_COLOR = '#F0F0F0';
const normalizarTexto = (texto: string = '') => texto.trim().toUpperCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");

type PointTuple = [number, number];

interface ViewConfig {
  center: PointTuple;
  zoom: number;
}

const PROVINCE_VIEW_CONFIG: Record<string, { desktop: ViewConfig; mobile?: ViewConfig }> = {
  "BUENOS AIRES": { desktop: { center: [-60.5, -37.3], zoom: 5 }, mobile: { center: [-60, -38], zoom: 5.5 } },
  "SANTA CRUZ": { desktop: { center: [-69.5, -49.3], zoom: 5 }, mobile: { center: [-69.5, -50], zoom: 4 } },
  "CIUDAD AUTONOMA DE BUENOS AIRES": { desktop: { center: [-58.44, -34.65], zoom: 150 } },
  "CHUBUT": { desktop: { center: [-68.5, -44.5], zoom: 5.5 }, mobile: { center: [-68, -44.5], zoom: 4.5 } },
  "SANTA FE": { desktop: { center: [-61, -31.2], zoom: 6 }, mobile: { center: [-61, -31.5], zoom: 7.5 } },
  "CORRIENTES": { desktop: { center: [-58, -29], zoom: 7 }, mobile: { center: [-57.5, -28.8], zoom: 9 } },
  "RIO NEGRO": { desktop: { center: [-67.5, -40], zoom: 5.5 }, mobile: { center: [-67.5, -40], zoom: 4.3 } },
  "SALTA": { desktop: { center: [-64.5, -24], zoom: 7 }, mobile: { center: [-65.5, -24.5], zoom: 6 } },
  "TIERRA DEL FUEGO": { desktop: { center: [-66.5, -54.2], zoom: 7 }, mobile: { center: [-66, -54], zoom: 7.5 } },
};

const LUPA_SIZE_RATIO = 0.2;
const MIN_LUPA_SIZE_PX = 100;
const MAX_LUPA_SIZE_PX = 180;

interface MapaNacionalProps {
  eleccionId: number;
  categoriaId: number;
  nivel: 'pais' | 'provincia' | 'municipio';
  nombreAmbito: string;
  nombreProvinciaActiva: string | undefined | null;
  provinciaDistritoId: string | null;
  onAmbitoSelect: (ambitoId: string, nivel: 'provincia' | 'municipio', nombre: string) => void;
  onVolver: () => void;
  isMobileView: boolean;
}

const desktopProjectionConfig = { scale: 700, center: [-65, -40] as [number, number] };
const mobileProjectionConfig = { scale: 1000, center: [-64, -43] as [number, number] };
const mobileSmallProjectionConfig = { scale: 750, center: [-64, -45] as [number, number] };

export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nombreProvinciaActiva, provinciaDistritoId, onAmbitoSelect, onVolver, isMobileView }: MapaNacionalProps) => {
  const isMobileSmall = useMediaQuery('(max-width: 380px)');

  const [position, setPosition] = useState({
    zoom: isMobileView ? 1.5 : 1.05,
    center: isMobileView ? mobileProjectionConfig.center : desktopProjectionConfig.center as PointTuple
  });
  const [isPanning, setIsPanning] = useState(false);
  const initialProvincePositionRef = useRef<ViewConfig | null>(null);

  const containerRef = useRef<HTMLDivElement | null>(null);
  const lupaRef = useRef<HTMLDivElement | null>(null);
  const cabaPathRef = useRef<SVGPathElement | null>(null);
  const isAnimatingRef = useRef(false);
  const initialLoadRef = useRef(true);

  const [lupaStyle, setLupaStyle] = useState<React.CSSProperties>({ opacity: 0 });

  const { data: mapaDataNacional } = useSuspenseQuery<ResultadoMapaDto[]>({
    queryKey: ['mapaResultados', eleccionId, categoriaId, null],
    queryFn: async () => {
      const url = `${API_BASE_URL}/elecciones/${eleccionId}/mapa-resultados?categoriaId=${categoriaId}`;
      const response = await axios.get(url);
      return response.data;
    },
  });

  const { data: geoDataNacional } = useSuspenseQuery<any>({
    queryKey: ['geoDataNacional'],
    queryFn: () => axios.get(`${assetBaseUrl}/maps/argentina-provincias.topojson`).then(res => res.data),
  });

  useEffect(() => {
    if (nivel === 'pais') {
      const currentMobileConfig = isMobileSmall ? mobileSmallProjectionConfig : mobileProjectionConfig;
      const currentMobileZoom = isMobileSmall ? 1.4 : 1.5;

      setPosition({
        zoom: isMobileView ? currentMobileZoom : 1.05,
        center: isMobileView ? currentMobileConfig.center : desktopProjectionConfig.center
      });
      initialProvincePositionRef.current = null;
    } else if (nivel === 'provincia') {
      const nombreNormalizado = normalizarTexto(nombreAmbito);
      const manualConfig = PROVINCE_VIEW_CONFIG[nombreNormalizado];
      
      let provinceConfig: ViewConfig | undefined;

      if (manualConfig) {
        provinceConfig = (isMobileView && manualConfig.mobile) ? manualConfig.mobile : manualConfig.desktop;
      } else {
        const provinciaGeo = geoDataNacional.objects.provincias.geometries.find((g: any) => normalizarTexto(g.properties.nombre) === nombreNormalizado);
        if (provinciaGeo) {
          const provinciaFeature = feature(geoDataNacional, provinciaGeo);
          const centroid = geoCentroid(provinciaFeature);
          provinceConfig = { zoom: isMobileView ? 8 : 7, center: centroid as PointTuple };
        }
      }

      if (provinceConfig) {
          setPosition(provinceConfig);
          initialProvincePositionRef.current = provinceConfig;
      }
    }
  }, [nivel, nombreAmbito, geoDataNacional, isMobileView, isMobileSmall]);

  const resultadosNacionalesPorNombre = new Map<string, ResultadoMapaDto>(mapaDataNacional.map(d => [normalizarTexto(d.ambitoNombre), d]));
  const nombreMunicipioSeleccionado = nivel === 'municipio' ? nombreAmbito : null;
  const handleCalculatedCenter = useCallback((center: PointTuple, zoom: number) => { setPosition({ center, zoom }); }, []);

  useEffect(() => {
    const updateLupaPosition = () => {
      if (nivel === 'pais' && cabaPathRef.current && containerRef.current) {
        const containerRect = containerRef.current.getBoundingClientRect();
        if (containerRect.width === 0) return;

        const cabaRect = cabaPathRef.current.getBoundingClientRect();
        const cabaCenterX = (cabaRect.left - containerRect.left) + cabaRect.width / 2;
        const cabaCenterY = (cabaRect.top - containerRect.top) + cabaRect.height / 2;

        const calculatedSize = containerRect.width * LUPA_SIZE_RATIO;
        const newLupaSize = Math.max(MIN_LUPA_SIZE_PX, Math.min(calculatedSize, MAX_LUPA_SIZE_PX));

        const horizontalOffset = newLupaSize * 0.5;
        const verticalOffset = newLupaSize * 0.2;

        setLupaStyle({
          position: 'absolute',
          top: `${cabaCenterY - verticalOffset}px`,
          left: `${cabaCenterX + horizontalOffset}px`,
          width: `${newLupaSize}px`,
          opacity: 1,
        });
      } else {
        setLupaStyle({ opacity: 0, pointerEvents: 'none' });
      }
    };

    isAnimatingRef.current = true;
    const handleResize = () => { if (!isAnimatingRef.current) updateLupaPosition(); };
    const resizeObserver = new ResizeObserver(handleResize);
    if (containerRef.current) resizeObserver.observe(containerRef.current);

    let timerId: NodeJS.Timeout;
    if (initialLoadRef.current && nivel === 'pais') {
      timerId = setTimeout(() => {
        updateLupaPosition();
        isAnimatingRef.current = false;
      }, 0);
      initialLoadRef.current = false;
    } else {
      timerId = setTimeout(() => {
        updateLupaPosition();
        isAnimatingRef.current = false;
      }, 800);
    }

    return () => {
      if (containerRef.current) resizeObserver.unobserve(containerRef.current);
      clearTimeout(timerId);
      isAnimatingRef.current = false;
    };
  }, [position, nivel]);

  const panEnabled =
    nivel === 'provincia' &&
    initialProvincePositionRef.current !== null &&
    position.zoom > initialProvincePositionRef.current.zoom &&
    !nombreMunicipioSeleccionado;

  const handleZoomIn = () => {
    if (!panEnabled && initialProvincePositionRef.current) {
      const newZoom = position.zoom * 1.8;
      if (newZoom > initialProvincePositionRef.current.zoom) {
        toast.success('Desplazamiento Habilitado', {
          icon: '🖐️',
          style: { background: '#32e5f1ff', color: 'white' },
          duration: 1000,
        });
      }
    }
    setPosition(prev => ({ ...prev, zoom: Math.min(prev.zoom * 1.8, 100) }));
  };

  const handleZoomOut = () => {
    if (panEnabled && initialProvincePositionRef.current) {
      const newZoom = position.zoom / 1.8;
      if (newZoom <= initialProvincePositionRef.current.zoom) {
        toast.error('Desplazamiento Deshabilitado', {
          icon: '🔒',
          style: { background: '#32e5f1ff', color: 'white' },
          duration: 1000,
        });
      }
    }
    setPosition(prev => {
      const newZoom = Math.max(prev.zoom / 1.8, 1);
      const initialPos = initialProvincePositionRef.current;
      if (initialPos && newZoom <= initialPos.zoom) return initialPos;
      return { ...prev, zoom: newZoom };
    });
  };

  const handleMoveEnd = (newPosition: { coordinates: PointTuple, zoom: number }) => {
    setPosition(prev => ({ ...prev, center: newPosition.coordinates }));
    setIsPanning(false);
  };

  const filterInteractionEvents = (event: any) => {
    if (event.sourceEvent && event.sourceEvent.type === 'wheel') return false;
    return panEnabled;
  };

  const showZoomControls = nivel === 'provincia';
  const isZoomOutDisabled =
    (nivel === 'provincia' && initialProvincePositionRef.current && position.zoom <= initialProvincePositionRef.current.zoom) ||
    (nivel === 'pais' && position.zoom <= (isMobileView ? 1.4 : 1.05));
    
  // 2. Todas las props 'className' ahora usan el objeto 'styles'
  const mapContainerClasses = `${styles.mapaComponenteContainer} ${panEnabled ? styles.mapPannable : styles.mapLocked}`;

  return (
    <div className={mapContainerClasses} ref={containerRef}>
      {showZoomControls && (
        <div className={styles.zoomControlsContainer}>
          <button onClick={handleZoomIn} className={styles.zoomBtn} title="Acercar">
            <span className={styles.zoomIconWrapper}><BiZoomIn /></span>
          </button>
          <button
            onClick={handleZoomOut}
            className={`${styles.zoomBtn} ${isZoomOutDisabled ? styles.disabled : ''}`}
            title="Alejar"
            disabled={isZoomOutDisabled}
          >
            <span className={styles.zoomIconWrapper}><BiZoomOut /></span>
          </button>
        </div>
      )}

      {nivel !== 'pais' && <button onClick={onVolver} className={styles.mapaVolverBtn}>← Volver</button>}

      <div className={styles.mapaRenderArea}>
        <ComposableMap
          projection="geoMercator"
          projectionConfig={isMobileSmall ? mobileSmallProjectionConfig : (isMobileView ? mobileProjectionConfig : desktopProjectionConfig)}
          style={{ width: "100%", height: "100%" }}
        >
          <ZoomableGroup
            center={position.center}
            zoom={position.zoom}
            onMoveStart={() => setIsPanning(true)}
            onMoveEnd={handleMoveEnd}
            filterZoomEvent={filterInteractionEvents}
            className={isPanning ? styles.panning : ''}
          >
            <Geographies geography={geoDataNacional}>
              {({ geographies }: { geographies: AmbitoGeography[] }) => geographies.map((geo) => {
                const nombreNormalizado = normalizarTexto(geo.properties.nombre);
                const esCABA = nombreNormalizado === 'CIUDAD AUTONOMA DE BUENOS AIRES';
                const resultado = resultadosNacionalesPorNombre.get(nombreNormalizado);
                const esProvinciaActiva = provinciaDistritoId && resultado?.ambitoId === provinciaDistritoId;

                return (
                  <Geography
                    key={geo.rsmKey}
                    geography={geo}
                    ref={esCABA ? cabaPathRef : undefined}
                    // 3. Las clases de react-simple-maps ahora deben ser globales o no funcionarán
                    // Como el CSS module ya las define con :global(), no necesitamos hacer nada aquí.
                    className={`rsm-geography ${nivel !== 'pais' ? 'rsm-geography-faded' : ''}`}
                    style={{ visibility: esCABA ? 'hidden' : (esProvinciaActiva ? 'hidden' : 'visible') }}
                    fill={nivel === 'pais' ? (resultado?.colorGanador || DEFAULT_MAP_COLOR) : FADED_BACKGROUND_COLOR}
                    onClick={() => !esCABA && resultado && onAmbitoSelect(resultado.ambitoId, 'provincia', resultado.ambitoNombre)}
                    data-tooltip-id="mapa-tooltip"
                    data-tooltip-content={geo.properties.nombre}
                  />
                );
              })}
            </Geographies>

            {provinciaDistritoId && nombreProvinciaActiva && (
              <Suspense fallback={null}>
                <MapaProvincial
                  eleccionId={eleccionId}
                  categoriaId={categoriaId}
                  distritoId={provinciaDistritoId}
                  nombreProvincia={nombreProvinciaActiva}
                  nombreMunicipioSeleccionado={nombreMunicipioSeleccionado}
                  onMunicipioSelect={(ambitoId, nombre) => onAmbitoSelect(ambitoId, 'municipio', nombre)}
                  onCalculatedCenter={handleCalculatedCenter}
                  nivel={nivel as 'provincia' | 'municipio'}
                />
              </Suspense>
            )}
          </ZoomableGroup>
        </ComposableMap>
      </div>

      {nivel === 'pais' && (
        <div id="caba-lupa-anchor" className={styles.cabaMagnifierContainer} style={lupaStyle} ref={lupaRef}>
          {(() => {
            const resultadoCABA = resultadosNacionalesPorNombre.get("CIUDAD AUTONOMA DE BUENOS AIRES");
            const fillColor = resultadoCABA?.colorGanador || DEFAULT_MAP_COLOR;
            const handleClick = () => {
              if (resultadoCABA) {
                onAmbitoSelect(resultadoCABA.ambitoId, 'provincia', resultadoCABA.ambitoNombre);
              }
            };
            return <CabaLupa fillColor={fillColor} onClick={handleClick} />;
          })()}
        </div>
      )}

      <Tooltip id="mapa-tooltip" key={nivel} />
    </div>
  );
};