'use client';

import { useEffect, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import type { LatLngBoundsExpression, LayerGroup, Map } from 'leaflet';

const MOROCCO_MAX_BOUNDS: LatLngBoundsExpression = [
  [20.0, -18.0],
  [36.5, -0.5],
];

const MOROCCO_DEFAULT_CENTER: [number, number] = [31.7917, -7.0926];
const MOROCCO_DEFAULT_ZOOM = 6;

export type MoroccoCity = {
  id: string;
  name: { en: string; fr: string; ar: string };
  lat?: number | null;
  lng?: number | null;
  price?: string;
  duration?: string;
  duration24h?: boolean;
  duration48h?: boolean;
  pickup?: boolean;
};

export function MoroccoLeafletMap({
  cities,
  selectedCity,
  hoveredCity,
  onSelect,
  onHover,
}: {
  cities: MoroccoCity[];
  selectedCity: string | null;
  hoveredCity: string | null;
  onSelect: (id: string) => void;
  onHover: (id: string | null) => void;
}) {
  const { i18n } = useTranslation();
  const currentLang = (i18n.language || 'fr') as 'en' | 'fr' | 'ar';

  const [[minLat, minLng], [maxLat, maxLng]] = MOROCCO_MAX_BOUNDS as [
    [number, number],
    [number, number],
  ];

  const containerRef = useRef<HTMLDivElement | null>(null);
  const mapRef = useRef<Map | null>(null);
  const layerGroupRef = useRef<LayerGroup | null>(null);

  const validCities = useMemo(() => {
    return cities
      .map((city) => ({
        ...city,
        lat: Number(city.lat),
        lng: Number(city.lng),
      }))
      .filter(
        (city) =>
          Number.isFinite(city.lat) &&
          Number.isFinite(city.lng) &&
          city.lat >= minLat &&
          city.lat <= maxLat &&
          city.lng >= minLng &&
          city.lng <= maxLng,
      );
  }, [cities, maxLat, maxLng, minLat, minLng]);

  const bounds: LatLngBoundsExpression | null = useMemo(() => {
    if (validCities.length === 0) return null;
    if (validCities.length === 1) {
      const only = validCities[0];
      const pad = 0.2;
      const candidate: LatLngBoundsExpression = [
        [only.lat - pad, only.lng - pad],
        [only.lat + pad, only.lng + pad],
      ];
      return candidate;
    }

    const lats = validCities.map((c) => c.lat);
    const lngs = validCities.map((c) => c.lng);
    const candidate: LatLngBoundsExpression = [
      [Math.min(...lats), Math.min(...lngs)],
      [Math.max(...lats), Math.max(...lngs)],
    ];
    const [[aLat, aLng], [bLat, bLng]] = candidate as [[number, number], [number, number]];
    if (![aLat, aLng, bLat, bLng].every(Number.isFinite)) return null;
    return candidate;
  }, [validCities]);

  // Create map once
  useEffect(() => {
    let cancelled = false;

    async function init() {
      if (!containerRef.current) return;
      if (mapRef.current) return;

      const L = await import('leaflet');
      if (cancelled) return;

      const map = L.map(containerRef.current, {
        zoomControl: false,
        scrollWheelZoom: true,
        maxBounds: MOROCCO_MAX_BOUNDS,
        maxBoundsViscosity: 0.9,
      }).setView(MOROCCO_DEFAULT_CENTER, MOROCCO_DEFAULT_ZOOM);

      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; OpenStreetMap contributors',
      }).addTo(map);

      const group = L.layerGroup().addTo(map);

      mapRef.current = map;
      layerGroupRef.current = group;
    }

    init();
    return () => {
      cancelled = true;
      if (mapRef.current) {
        mapRef.current.remove();
        mapRef.current = null;
      }
      layerGroupRef.current = null;
    };
  }, []);

  // Update markers + fit bounds
  useEffect(() => {
    let cancelled = false;

    async function update() {
      const map = mapRef.current;
      const layerGroup = layerGroupRef.current;
      if (!map || !layerGroup) return;

      const L = await import('leaflet');
      if (cancelled) return;

      layerGroup.clearLayers();

      for (const city of validCities) {
        const isActive = selectedCity === city.id || hoveredCity === city.id;
        const marker = L.circleMarker([city.lat, city.lng], {
          radius: isActive ? 10 : 6,
          color: '#3A4A9C',
          weight: 2,
          fillColor: '#3A4A9C',
          fillOpacity: isActive ? 0.85 : 0.6,
        });

        marker.on('click', () => onSelect(city.id));
        marker.on('mouseover', () => onHover(city.id));
        marker.on('mouseout', () => onHover(null));

        // Hover label (like the previous SVG version)
        marker.bindTooltip(city.name[currentLang], {
          direction: 'top',
          offset: [0, -8],
          opacity: 1,
          sticky: true,
          className: 'dropex-city-tooltip',
        });

        if (isActive) {
          marker.openTooltip();
        }

        marker.addTo(layerGroup);
      }

      if (bounds) {
        map.fitBounds(bounds, { padding: [32, 32] });
      } else {
        map.setView(MOROCCO_DEFAULT_CENTER, MOROCCO_DEFAULT_ZOOM);
      }

      // Ensure proper rendering when the container size changes (e.g., responsive layout)
      setTimeout(() => {
        map.invalidateSize();
      }, 0);
    }

    update();
    return () => {
      cancelled = true;
    };
  }, [bounds, currentLang, hoveredCity, onHover, onSelect, selectedCity, validCities]);

  return (
    <div ref={containerRef} className="w-full h-full" />
  );
}
