import { useEffect, useMemo, useRef } from "react";
import maplibregl, { type GeoJSONSource, type LngLatBoundsLike, type Map as MapLibreMap, type MapLayerMouseEvent } from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";
import { buildDirectionsOptions } from "@/lib/mapDirections";
import { buildMaterialReturnFinalPdfViewerHref } from "@/lib/materialReturnFinalPdf";
import { getAssociationThematicLabel } from "@shared/associationThematics";

type PointFeature = {
  type: "Feature";
  properties: FeatureProperties;
  geometry: {
    type: "Point";
    coordinates: [number, number];
  };
};

type PolygonFeature = {
  type: "Feature";
  properties: FeatureProperties;
  geometry: {
    type: "Polygon";
    coordinates: [Array<[number, number]>];
  };
};

type SimpleFeatureCollection = {
  type: "FeatureCollection";
  features: Array<PointFeature | PolygonFeature>;
};

type MapAssociationEntry = {
  id: number;
  nomAssociation: string;
  ville: string | null;
  thematiques?: string[] | null;
  objetAssociation: string | null;
  siteWeb?: string | null;
  latitude: number | null;
  longitude: number | null;
  registered: boolean;
  publicUrl: string;
};

type LogisticsEvent = {
  requestId: number;
  title: string;
  associationName: string;
  commune: string;
  manifestationStart: string;
  manifestationEnd: string;
  pickupDate: string;
  restitutionDate: string;
  useStartDate: string;
  useEndDate: string;
  requestedItems: Array<{
    key: string;
    label: string;
    quantity: number;
    granted: boolean;
    requested: boolean;
    extra: string;
  }>;
  boardState: string;
  boardStateLabel: string;
  logisticServiceLabel: string;
  issueFlag: boolean;
  finalPdfUrl: string | null;
  uploadLink: string | null;
};

type AssociationPublicMapProps = {
  associations: MapAssociationEntry[];
  mode: "annuaire" | "densite" | "logistique";
  selectedAssociationId?: number | null;
  onSelectAssociation?: (id: number) => void;
  logisticsEvents?: LogisticsEvent[];
  selectedLogisticsRequestId?: number | null;
  onSelectLogistics?: (requestId: number) => void;
  onOpenLogisticsRequest?: (requestId: number) => void;
  logisticsMarkerClickMode?: "select-first" | "open-direct";
  radiusCenter?: { latitude: number; longitude: number } | null;
  radiusKm?: number;
  styleUrl?: string;
  heightClassName?: string;
};

type FeatureProperties = Record<string, string | number | boolean | null>;

const logisticsStateColors: Record<string, string> = {
  a_attribuer: "#64748b",
  planifie: "#2563eb",
  terrain: "#d97706",
  retard: "#dc2626",
  conforme: "#16a34a",
  litige: "#ea580c",
};

function escapeHtml(value: string | null | undefined) {
  return String(value || "")
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

function getThematicColor(thematique?: string | null) {
  switch (thematique) {
    case "culture_loisirs":
      return "#7c3aed";
    case "social_sante":
      return "#dc2626";
    case "education_formation":
      return "#2563eb";
    case "economie_territoire":
      return "#b45309";
    case "environnement_patrimoine":
      return "#15803d";
    case "institutions_divers":
      return "#475569";
    default:
      return "#0f5c89";
  }
}

function getHeatColor(count: number, maxCount: number) {
  if (maxCount <= 1) return "#0f5c89";
  const ratio = count / maxCount;
  if (ratio > 0.75) return "#b91c1c";
  if (ratio > 0.5) return "#ea580c";
  if (ratio > 0.25) return "#f59e0b";
  return "#2563eb";
}

function formatDateFr(value?: string | null) {
  if (!value) return "-";
  try {
    return new Date(value).toLocaleDateString("fr-FR", {
      day: "2-digit",
      month: "2-digit",
      year: "numeric",
    });
  } catch {
    return value;
  }
}

function isDateWithinTodayRange(start?: string | null, end?: string | null) {
  const today = new Date().toISOString().slice(0, 10);
  const normalizedStart = String(start || "").slice(0, 10);
  const normalizedEnd = String(end || normalizedStart).slice(0, 10);
  if (!normalizedStart || !normalizedEnd) return false;
  return normalizedStart <= today && today <= normalizedEnd;
}

function toFeature(properties: FeatureProperties, longitude: number, latitude: number) {
  return {
    type: "Feature" as const,
    properties,
    geometry: {
      type: "Point" as const,
      coordinates: [longitude, latitude] as [number, number],
    },
  };
}

function updateGeoJsonSource(map: MapLibreMap, sourceId: string, data: SimpleFeatureCollection) {
  const source = map.getSource(sourceId) as GeoJSONSource | undefined;
  if (source) {
    source.setData(data);
  }
}

function buildBoundsFromFeatures(features: PointFeature[]) {
  if (features.length === 0) return null;
  const first = features[0].geometry.coordinates;
  const bounds = new maplibregl.LngLatBounds(first as [number, number], first as [number, number]);
  for (const feature of features.slice(1)) {
    bounds.extend(feature.geometry.coordinates as [number, number]);
  }
  return bounds as LngLatBoundsLike;
}

function buildAssociationPopup(properties: FeatureProperties) {
  const thematiques = String(properties.thematiques || "")
    .split("||")
    .filter(Boolean);
  const directionsLinks = buildDirectionsOptions({
    latitude: typeof properties.latitude === "number" ? properties.latitude : null,
    longitude: typeof properties.longitude === "number" ? properties.longitude : null,
    destinationLabel: [properties.nomAssociation, properties.ville].filter(Boolean).join(", "),
  })
    .map((option) => `<a href="${escapeHtml(option.href)}" target="_blank" rel="noopener noreferrer">${escapeHtml(option.label)}</a>`)
    .join("");

  return `<div class="association-map-popup-card">
    <div class="association-map-popup-eyebrow">Association</div>
    <strong class="association-map-popup-title">${escapeHtml(String(properties.nomAssociation || ""))}</strong>
    <span class="association-map-popup-meta">${escapeHtml(String(properties.ville || "Commune non renseignée"))}</span>
    ${thematiques.length ? `<span class="association-map-popup-tags">${escapeHtml(thematiques.join(" • "))}</span>` : ""}
    ${properties.objetAssociation ? `<span class="association-map-popup-body">${escapeHtml(String(properties.objetAssociation))}</span>` : ""}
    <div class="association-map-popup-actions">
      ${directionsLinks}
      ${properties.siteWeb ? `<a href="${escapeHtml(String(properties.siteWeb))}" target="_blank" rel="noopener noreferrer">Site web</a>` : ""}
      ${properties.publicUrl ? `<a href="${escapeHtml(String(properties.publicUrl))}">Voir la fiche</a>` : ""}
    </div>
  </div>`;
}

function buildDensityPopup(properties: FeatureProperties) {
  return `<div class="association-map-popup-card">
    <div class="association-map-popup-eyebrow">Lecture territoriale</div>
    <strong class="association-map-popup-title">${escapeHtml(String(properties.ville || "Commune non renseignée"))}</strong>
    <span class="association-map-popup-meta">${properties.count} association(s)</span>
    ${properties.dominantThematique ? `<span class="association-map-popup-body">Thématique dominante: ${escapeHtml(String(properties.dominantThematique))}</span>` : ""}
  </div>`;
}

function buildLogisticsPopup(properties: FeatureProperties) {
  const directionsLinks = buildDirectionsOptions({
    latitude: typeof properties.latitude === "number" ? properties.latitude : null,
    longitude: typeof properties.longitude === "number" ? properties.longitude : null,
    destinationLabel: [properties.associationName, properties.commune].filter(Boolean).join(", "),
  })
    .map((option) => `<a href="${escapeHtml(option.href)}" target="_blank" rel="noopener noreferrer">${escapeHtml(option.label)}</a>`)
    .join("");
  const finalPdfViewerHref = properties.finalPdfUrl
    ? buildMaterialReturnFinalPdfViewerHref({
        url: String(properties.finalPdfUrl),
        returnTo: "/associations/carte",
        title: "Consulter le PDF final de restitution",
        downloadName: `fiche-finale-restitution-${String(properties.requestId || "materiel")}.pdf`,
      })
    : "";
  const requestUrl = properties.requestId ? `/dashboard/requests/${String(properties.requestId)}` : "";

  return `<div class="association-map-popup-card">
    <div class="association-map-popup-eyebrow">Logistique</div>
    <strong class="association-map-popup-title">${escapeHtml(String(properties.associationName || ""))}</strong>
    <span class="association-map-popup-meta">${escapeHtml(String(properties.commune || "Commune non renseignée"))}</span>
    <span class="association-map-popup-state">${escapeHtml(String(properties.boardStateLabel || ""))}</span>
    <span class="association-map-popup-body">Usage: ${escapeHtml(String(properties.manifestationStartLabel || "-"))} au ${escapeHtml(String(properties.manifestationEndLabel || "-"))}</span>
    <span class="association-map-popup-body">Matériel: ${escapeHtml(String(properties.requestedItemsLabel || "Non renseigné"))}</span>
    ${properties.logisticServiceLabel ? `<span class="association-map-popup-body">Service: ${escapeHtml(String(properties.logisticServiceLabel))}</span>` : ""}
    <div class="association-map-popup-actions">
      ${requestUrl ? `<a href="${escapeHtml(requestUrl)}">Ouvrir dossier</a>` : ""}
      ${directionsLinks}
      ${properties.finalPdfUrl ? `<a href="${escapeHtml(finalPdfViewerHref)}">PDF final</a>` : ""}
      ${properties.uploadLink ? `<a href="${escapeHtml(String(properties.uploadLink))}" target="_blank" rel="noopener noreferrer">Lien terrain</a>` : ""}
    </div>
  </div>`;
}

function normalizeMapStyleUrl(styleUrl: string) {
  if (typeof window === "undefined") {
    return styleUrl;
  }

  const isLocalHost = ["localhost", "127.0.0.1"].includes(window.location.hostname);
  if (!isLocalHost) {
    return styleUrl;
  }

  try {
    const parsed = new URL(styleUrl);
    if (
      ["www.portail-association973.com", "preprod.portail-association973.com"].includes(parsed.hostname)
      && (parsed.pathname.startsWith("/map-styles/") || parsed.pathname.startsWith("/map-tiles/") || parsed.pathname.startsWith("/data/"))
    ) {
      return `${parsed.pathname}${parsed.search}`;
    }
  } catch {
    return styleUrl;
  }

  return styleUrl;
}

export function AssociationPublicMap({
  associations,
  mode,
  selectedAssociationId,
  onSelectAssociation,
  logisticsEvents = [],
  selectedLogisticsRequestId,
  onSelectLogistics,
  onOpenLogisticsRequest,
  logisticsMarkerClickMode = "select-first",
  radiusCenter = null,
  radiusKm = 0,
  styleUrl = "/map-styles/openmaptiles-positron/style.json",
  heightClassName = "h-[620px]",
}: AssociationPublicMapProps) {
  const mapContainerRef = useRef<HTMLDivElement | null>(null);
  const mapRef = useRef<MapLibreMap | null>(null);
  const popupRef = useRef<maplibregl.Popup | null>(null);
  const interactiveBoundRef = useRef(false);
  const modeRef = useRef(mode);
  const selectedLogisticsRequestIdRef = useRef<number | null | undefined>(selectedLogisticsRequestId);
  const onSelectLogisticsRef = useRef(onSelectLogistics);
  const onOpenLogisticsRequestRef = useRef(onOpenLogisticsRequest);
  const logisticsMarkerClickModeRef = useRef(logisticsMarkerClickMode);
  modeRef.current = mode;
  selectedLogisticsRequestIdRef.current = selectedLogisticsRequestId;
  onSelectLogisticsRef.current = onSelectLogistics;
  onOpenLogisticsRequestRef.current = onOpenLogisticsRequest;
  logisticsMarkerClickModeRef.current = logisticsMarkerClickMode;
  const resolvedStyleUrl = useMemo(() => normalizeMapStyleUrl(styleUrl), [styleUrl]);

  const validAssociations = useMemo(
    () => associations.filter((item) => item.latitude !== null && item.longitude !== null),
    [associations]
  );

  const associationLookup = useMemo(() => {
    const lookup = new Map<string, MapAssociationEntry>();
    validAssociations.forEach((entry) => {
      const baseKey = entry.nomAssociation.trim().toLowerCase();
      lookup.set(baseKey, entry);
      if (entry.ville) {
        lookup.set(`${baseKey}::${entry.ville.trim().toLowerCase()}`, entry);
      }
    });
    return lookup;
  }, [validAssociations]);

  const communeDensity = useMemo(() => {
    const groups = new Map<
      string,
      {
        ville: string;
        count: number;
        latitudeTotal: number;
        longitudeTotal: number;
        thematiques: string[];
      }
    >();

    validAssociations.forEach((entry) => {
      const key = entry.ville || `association-${entry.id}`;
      const group = groups.get(key) || {
        ville: entry.ville || "Commune non renseignée",
        count: 0,
        latitudeTotal: 0,
        longitudeTotal: 0,
        thematiques: [],
      };
      group.count += 1;
      group.latitudeTotal += entry.latitude as number;
      group.longitudeTotal += entry.longitude as number;
      group.thematiques.push(...(entry.thematiques || []));
      groups.set(key, group);
    });

    return Array.from(groups.values()).map((group) => {
      const counts = group.thematiques.reduce<Record<string, number>>((acc, value) => {
        acc[value] = (acc[value] || 0) + 1;
        return acc;
      }, {});
      const dominant = Object.entries(counts).sort((a, b) => b[1] - a[1])[0]?.[0] || null;
      return {
        ...group,
        dominantThematique: dominant ? getAssociationThematicLabel(dominant) : null,
        latitude: group.latitudeTotal / group.count,
        longitude: group.longitudeTotal / group.count,
      };
    });
  }, [validAssociations]);

  const maxDensityCount = useMemo(
    () => communeDensity.reduce((max, group) => Math.max(max, group.count), 0),
    [communeDensity]
  );

  const logisticsFeatures = useMemo(() => {
    return logisticsEvents.flatMap((event) => {
      const associationNameKey = event.associationName.trim().toLowerCase();
      const communeKey = event.commune?.trim().toLowerCase();
      const associationMatch = (communeKey && associationLookup.get(`${associationNameKey}::${communeKey}`))
        || associationLookup.get(associationNameKey);
      if (!associationMatch?.latitude || !associationMatch?.longitude) return [];

      const active = isDateWithinTodayRange(event.useStartDate, event.useEndDate);
      return [
        toFeature(
          {
            requestId: event.requestId,
            associationName: event.associationName,
            commune: event.commune || associationMatch.ville,
            latitude: associationMatch.latitude,
            longitude: associationMatch.longitude,
            boardStateLabel: event.boardStateLabel,
            logisticServiceLabel: event.logisticServiceLabel,
            finalPdfUrl: event.finalPdfUrl,
            uploadLink: event.uploadLink,
            manifestationStartLabel: formatDateFr(event.manifestationStart),
            manifestationEndLabel: formatDateFr(event.manifestationEnd),
            requestedItemsLabel: event.requestedItems.map((item) => `${item.label} x${item.quantity}`).join(" • ") || "Non renseigné",
            color: logisticsStateColors[event.boardState] || "#0f5c89",
            radius: selectedLogisticsRequestId === event.requestId ? 13 : active ? 11 : 9,
          },
          associationMatch.longitude,
          associationMatch.latitude
        ),
      ];
    });
  }, [associationLookup, logisticsEvents, selectedLogisticsRequestId]);

  const associationFeatureCollection = useMemo<SimpleFeatureCollection>(() => ({
    type: "FeatureCollection",
    features: validAssociations.map((entry) =>
      toFeature(
        {
          id: entry.id,
          nomAssociation: entry.nomAssociation,
          ville: entry.ville,
          thematiques: (entry.thematiques || []).map((value) => getAssociationThematicLabel(value)).join("||"),
          objetAssociation: entry.objetAssociation,
          siteWeb: entry.siteWeb || "",
          publicUrl: entry.publicUrl,
          latitude: entry.latitude,
          longitude: entry.longitude,
          color: getThematicColor(entry.thematiques?.[0]),
          radius: selectedAssociationId === entry.id ? 11 : 8,
        },
        entry.longitude as number,
        entry.latitude as number
      )
    ),
  }), [selectedAssociationId, validAssociations]);

  const densityFeatureCollection = useMemo<SimpleFeatureCollection>(() => ({
    type: "FeatureCollection",
    features: communeDensity.map((group) =>
      toFeature(
        {
          ville: group.ville,
          count: group.count,
          dominantThematique: group.dominantThematique || "",
          color: getHeatColor(group.count, maxDensityCount),
          radiusMeters: Math.max(6000, 4000 + group.count * 1800),
          label: String(group.count),
        },
        group.longitude,
        group.latitude
      )
    ),
  }), [communeDensity, maxDensityCount]);

  const logisticsFeatureCollection = useMemo<SimpleFeatureCollection>(() => ({
    type: "FeatureCollection",
    features: logisticsFeatures,
  }), [logisticsFeatures]);

  useEffect(() => {
    if (!mapContainerRef.current) return;

    const map = new maplibregl.Map({
      container: mapContainerRef.current,
      style: resolvedStyleUrl,
      center: [-52.75, 4.95],
      zoom: 8,
    });

    map.addControl(new maplibregl.NavigationControl(), "top-right");
    mapRef.current = map;
    popupRef.current = new maplibregl.Popup({
      closeButton: false,
      closeOnClick: false,
      maxWidth: "340px",
      className: "association-public-map-popup",
    });

    const bindInteractivity = () => {
      if (interactiveBoundRef.current) return;
      interactiveBoundRef.current = true;

      map.on("click", "association-unclustered", (event: MapLayerMouseEvent) => {
        const feature = event.features?.[0];
        if (!feature || feature.geometry.type !== "Point") return;
        const props = feature.properties || {};
        onSelectAssociation?.(Number(props.id));
        popupRef.current
          ?.setLngLat(feature.geometry.coordinates as [number, number])
          .setHTML(buildAssociationPopup(props as FeatureProperties))
          .addTo(map);
      });

      map.on("click", "association-clusters", (event: MapLayerMouseEvent) => {
        const feature = event.features?.[0];
        if (!feature || feature.geometry.type !== "Point") return;
        const pointFeature = feature as unknown as PointFeature;
        const clusterId = pointFeature.properties?.cluster_id;
        const source = map.getSource("associations") as (GeoJSONSource & {
          getClusterExpansionZoom?: (clusterId: number, cb: (error: Error | null, zoom: number) => void) => void;
        }) | undefined;
        if (!source || clusterId === undefined) return;
        source.getClusterExpansionZoom?.(Number(clusterId), (error: Error | null, zoom: number) => {
          if (error) return;
          map.easeTo({
            center: pointFeature.geometry.coordinates,
            zoom,
          });
        });
      });

      map.on("click", "density-circles", (event: MapLayerMouseEvent) => {
        const feature = event.features?.[0];
        if (!feature || feature.geometry.type !== "Point") return;
        popupRef.current
          ?.setLngLat(feature.geometry.coordinates as [number, number])
          .setHTML(buildDensityPopup(feature.properties as FeatureProperties))
          .addTo(map);
      });

      map.on("click", "logistics-circles", (event: MapLayerMouseEvent) => {
        const feature = event.features?.[0];
        if (!feature || feature.geometry.type !== "Point") return;
        const requestId = Number(feature.properties?.requestId);
        if (logisticsMarkerClickModeRef.current === "open-direct") {
          onSelectLogisticsRef.current?.(requestId);
          onOpenLogisticsRequestRef.current?.(requestId);
        } else if (selectedLogisticsRequestIdRef.current === requestId) {
          onOpenLogisticsRequestRef.current?.(requestId);
        } else {
          onSelectLogisticsRef.current?.(requestId);
        }
        popupRef.current
          ?.setLngLat(feature.geometry.coordinates as [number, number])
          .setHTML(buildLogisticsPopup(feature.properties as FeatureProperties))
          .addTo(map);
      });

      for (const layerId of ["association-unclustered", "association-clusters", "density-circles", "logistics-circles"]) {
        map.on("mouseenter", layerId, () => {
          map.getCanvas().style.cursor = "pointer";
        });
        map.on("mouseleave", layerId, () => {
          map.getCanvas().style.cursor = "";
        });
      }
    };

    const ensureLayers = () => {
      if (!map.getSource("associations")) {
        map.addSource("associations", {
          type: "geojson",
          data: associationFeatureCollection,
          cluster: true,
          clusterMaxZoom: 10,
          clusterRadius: 50,
        });
      }
      if (!map.getLayer("association-clusters")) {
        map.addLayer({
          id: "association-clusters",
          type: "circle",
          source: "associations",
          filter: ["has", "point_count"],
          paint: {
            "circle-color": "#0f5c89",
            "circle-radius": [
              "step",
              ["get", "point_count"],
              18,
              10,
              24,
              30,
              30,
            ],
            "circle-stroke-width": 3,
            "circle-stroke-color": "#ffffff",
          },
        });
      }
      if (!map.getLayer("association-cluster-count")) {
        map.addLayer({
          id: "association-cluster-count",
          type: "symbol",
          source: "associations",
          filter: ["has", "point_count"],
          layout: {
            "text-field": ["get", "point_count_abbreviated"],
            "text-size": 12,
            "text-font": ["Open Sans Bold"],
          },
          paint: {
            "text-color": "#ffffff",
          },
        });
      }
      if (!map.getLayer("association-unclustered")) {
        map.addLayer({
          id: "association-unclustered",
          type: "circle",
          source: "associations",
          filter: ["!", ["has", "point_count"]],
          paint: {
            "circle-color": ["coalesce", ["get", "color"], "#0f5c89"],
            "circle-radius": ["coalesce", ["get", "radius"], 8],
            "circle-stroke-width": 2,
            "circle-stroke-color": "#ffffff",
            "circle-opacity": 0.95,
          },
        });
      }

      if (!map.getSource("density")) {
        map.addSource("density", {
          type: "geojson",
          data: densityFeatureCollection,
        });
      }
      if (!map.getLayer("density-circles")) {
        map.addLayer({
          id: "density-circles",
          type: "circle",
          source: "density",
          paint: {
            "circle-color": ["coalesce", ["get", "color"], "#2563eb"],
            "circle-radius": [
              "interpolate",
              ["linear"],
              ["zoom"],
              5,
              14,
              12,
              32,
            ],
            "circle-opacity": 0.28,
            "circle-stroke-width": 1.5,
            "circle-stroke-color": ["coalesce", ["get", "color"], "#2563eb"],
          },
        });
      }
      if (!map.getLayer("density-labels")) {
        map.addLayer({
          id: "density-labels",
          type: "symbol",
          source: "density",
          layout: {
            "text-field": ["get", "label"],
            "text-size": 13,
            "text-font": ["Open Sans Bold"],
          },
          paint: {
            "text-color": "#0f172a",
            "text-halo-color": "#ffffff",
            "text-halo-width": 1.5,
          },
        });
      }

      if (!map.getSource("logistics")) {
        map.addSource("logistics", {
          type: "geojson",
          data: logisticsFeatureCollection,
        });
      }
      if (!map.getLayer("logistics-circles")) {
        map.addLayer({
          id: "logistics-circles",
          type: "circle",
          source: "logistics",
          paint: {
            "circle-color": ["coalesce", ["get", "color"], "#0f5c89"],
            "circle-radius": ["coalesce", ["get", "radius"], 9],
            "circle-stroke-width": 2,
            "circle-stroke-color": "#ffffff",
            "circle-opacity": 0.95,
          },
        });
      }

      if (!map.getSource("radius")) {
        map.addSource("radius", {
          type: "geojson",
          data: {
            type: "FeatureCollection",
            features: [],
          },
        });
      }
      if (!map.getLayer("radius-fill")) {
        map.addLayer({
          id: "radius-fill",
          type: "fill",
          source: "radius",
          paint: {
            "fill-color": "#93c5fd",
            "fill-opacity": 0.12,
          },
        });
      }
      if (!map.getLayer("radius-outline")) {
        map.addLayer({
          id: "radius-outline",
          type: "line",
          source: "radius",
          paint: {
            "line-color": "#2563eb",
            "line-width": 2,
            "line-opacity": 0.7,
          },
        });
      }

      bindInteractivity();
    };

    map.on("load", ensureLayers);
    map.on("styledata", ensureLayers);

    return () => {
      popupRef.current?.remove();
      popupRef.current = null;
      interactiveBoundRef.current = false;
      map.remove();
      mapRef.current = null;
    };
  }, [resolvedStyleUrl, onSelectAssociation, onSelectLogistics]);

  useEffect(() => {
    const map = mapRef.current;
    if (!map || !map.isStyleLoaded()) return;

    updateGeoJsonSource(map, "associations", associationFeatureCollection);
    updateGeoJsonSource(map, "density", densityFeatureCollection);
    updateGeoJsonSource(map, "logistics", logisticsFeatureCollection);
  }, [associationFeatureCollection, densityFeatureCollection, logisticsFeatureCollection]);

  useEffect(() => {
    const map = mapRef.current;
    if (!map || !map.isStyleLoaded()) return;

    const radiusFeatureCollection: SimpleFeatureCollection = radiusCenter && radiusKm > 0
      ? {
          type: "FeatureCollection",
          features: [
            {
              type: "Feature",
              properties: {},
              geometry: {
                type: "Polygon",
                coordinates: [Array.from({ length: 65 }, (_, index) => {
                  const angle = (index / 64) * Math.PI * 2;
                  const earthRadius = 6371;
                  const lat = radiusCenter.latitude + (radiusKm / earthRadius) * (180 / Math.PI) * Math.sin(angle);
                  const lng = radiusCenter.longitude + (radiusKm / earthRadius) * (180 / Math.PI) * Math.cos(angle) / Math.cos((radiusCenter.latitude * Math.PI) / 180);
                  return [lng, lat];
                })],
              },
            },
          ],
        }
      : { type: "FeatureCollection", features: [] };

    updateGeoJsonSource(map, "radius", radiusFeatureCollection);
  }, [radiusCenter, radiusKm]);

  useEffect(() => {
    const map = mapRef.current;
    if (!map || !map.isStyleLoaded()) return;
    const visibilityByMode: Record<typeof mode, { associations: "visible" | "none"; density: "visible" | "none"; logistics: "visible" | "none" }> = {
      annuaire: { associations: "visible", density: "none", logistics: "none" },
      densite: { associations: "none", density: "visible", logistics: "none" },
      logistique: { associations: "none", density: "none", logistics: "visible" },
    };
    const visibility = visibilityByMode[mode];

    const setVisibility = (layerId: string, value: "visible" | "none") => {
      if (map.getLayer(layerId)) map.setLayoutProperty(layerId, "visibility", value);
    };

    setVisibility("association-clusters", visibility.associations);
    setVisibility("association-cluster-count", visibility.associations);
    setVisibility("association-unclustered", visibility.associations);
    setVisibility("density-circles", visibility.density);
    setVisibility("density-labels", visibility.density);
    setVisibility("logistics-circles", visibility.logistics);
  }, [mode]);

  useEffect(() => {
    const map = mapRef.current;
    if (!map || !map.isStyleLoaded()) return;

    let bounds: LngLatBoundsLike | null = null;
    if (mode === "annuaire") {
      bounds = buildBoundsFromFeatures(associationFeatureCollection.features as PointFeature[]);
    } else if (mode === "densite") {
      bounds = buildBoundsFromFeatures(densityFeatureCollection.features as PointFeature[]);
    } else if (mode === "logistique") {
      bounds = buildBoundsFromFeatures(logisticsFeatureCollection.features as PointFeature[]);
    }

    if (bounds) {
      map.fitBounds(bounds, { padding: 28, maxZoom: 12 });
    }
  }, [mode, associationFeatureCollection, densityFeatureCollection, logisticsFeatureCollection]);

  useEffect(() => {
    const map = mapRef.current;
    if (!map || !map.isStyleLoaded() || !selectedAssociationId) return;
    const feature = (associationFeatureCollection.features as PointFeature[])
      .find((entry) => Number(entry.properties.id) === selectedAssociationId);
    if (!feature) return;
    map.easeTo({
      center: feature.geometry.coordinates as [number, number],
      zoom: Math.max(map.getZoom(), 12),
    });
    popupRef.current
      ?.setLngLat(feature.geometry.coordinates as [number, number])
      .setHTML(buildAssociationPopup(feature.properties))
      .addTo(map);
  }, [associationFeatureCollection, selectedAssociationId]);

  useEffect(() => {
    const map = mapRef.current;
    if (!map || !map.isStyleLoaded() || !selectedLogisticsRequestId) return;
    const feature = (logisticsFeatureCollection.features as PointFeature[])
      .find((entry) => Number(entry.properties.requestId) === selectedLogisticsRequestId);
    if (!feature) return;
    map.easeTo({
      center: feature.geometry.coordinates as [number, number],
      zoom: Math.max(map.getZoom(), 12),
    });
    popupRef.current
      ?.setLngLat(feature.geometry.coordinates as [number, number])
      .setHTML(buildLogisticsPopup(feature.properties))
      .addTo(map);
  }, [logisticsFeatureCollection, selectedLogisticsRequestId]);

  const modeLabel = mode === "annuaire" ? "Annuaire géographique" : mode === "densite" ? "Densité territoriale" : "Pilotage logistique";
  const helperLabel =
    mode === "annuaire"
      ? `${validAssociations.length} repère(s) cartographiques`
      : mode === "densite"
        ? `${communeDensity.length} pôle(s) de lecture`
        : `${logisticsFeatures.length} mission(s) cartographiée(s)`;

  return (
    <div className="relative">
      <style>{`
        .association-public-map-popup .maplibregl-popup-content {
          padding: 0;
          border-radius: 14px;
          box-shadow: 0 18px 38px rgba(15, 23, 42, 0.18);
          border: 1px solid rgba(148, 163, 184, 0.28);
          overflow: hidden;
        }
        .association-public-map-popup .maplibregl-popup-tip {
          border-top-color: rgba(255,255,255,0.98);
        }
        .association-map-popup-card {
          min-width: 240px;
          display: flex;
          flex-direction: column;
          gap: 8px;
          padding: 14px 16px;
          background: rgba(255,255,255,0.98);
        }
        .association-map-popup-eyebrow {
          font-size: 11px;
          font-weight: 700;
          letter-spacing: 0.04em;
          text-transform: uppercase;
          color: #0f766e;
        }
        .association-map-popup-title {
          font-size: 15px;
          line-height: 1.35;
          color: #0f172a;
        }
        .association-map-popup-meta {
          font-size: 12px;
          color: #475569;
        }
        .association-map-popup-tags,
        .association-map-popup-state {
          display: inline-flex;
          align-self: flex-start;
          padding: 4px 8px;
          border-radius: 999px;
          background: rgba(15, 118, 110, 0.1);
          color: #115e59;
          font-size: 12px;
          font-weight: 600;
        }
        .association-map-popup-body {
          font-size: 12px;
          line-height: 1.5;
          color: #334155;
        }
        .association-map-popup-actions {
          display: flex;
          flex-wrap: wrap;
          gap: 10px;
          margin-top: 2px;
        }
        .association-map-popup-actions a {
          color: #0f5c89;
          font-size: 12px;
          font-weight: 600;
          text-decoration: none;
        }
        .association-map-popup-actions a:hover {
          text-decoration: underline;
        }
      `}</style>

      <div className="pointer-events-none absolute left-4 top-4 z-10 flex max-w-[68%] flex-wrap gap-2">
        <span className="rounded-full border border-white/60 bg-slate-950/78 px-3 py-1 text-xs font-medium text-white backdrop-blur">
          {modeLabel}
        </span>
        <span className="rounded-full border border-white/70 bg-white/88 px-3 py-1 text-xs font-medium text-slate-700 shadow-sm backdrop-blur">
          {helperLabel}
        </span>
      </div>

      <div className="pointer-events-none absolute bottom-4 left-4 z-10 hidden max-w-[70%] rounded-xl border border-white/70 bg-white/88 px-4 py-3 text-xs text-slate-600 shadow-sm backdrop-blur md:block">
        {mode === "annuaire"
          ? "Clique sur un point ou une fiche pour centrer l’association et ouvrir sa lecture rapide."
          : mode === "densite"
            ? "Les cercles plus intenses indiquent les communes où la présence associative est la plus dense."
            : "La lecture logistique aide à repérer où se concentrent les missions terrain et les restitutions."}
      </div>

      <div
        ref={mapContainerRef}
        className={`${heightClassName} w-full overflow-hidden rounded-2xl border border-slate-200 bg-slate-100 shadow-[0_18px_40px_rgba(15,23,42,0.08)]`}
      />
    </div>
  );
}
