// -----------------------------------------------------------------------------
// Immo-Ka — Agrégateur de propriétés à vendre (province de Québec)
// Auteur : Simon-Pierre Boucher — contact@spboucher.ai
// components/MapView.tsx : carte interactive MapLibre GL
//   · chargée paresseusement (React.lazy) — le bundle carte ne pèse rien tant
//     que l'utilisateur reste en vue liste
//   · données GeoJSON (/api/listings.geojson) synchronisées avec les filtres
//   · clustering natif, marqueurs-prix, fiche popup, tuiles OpenFreeMap
// -----------------------------------------------------------------------------
import { useEffect, useRef } from "react";
import { useNavigate } from "react-router-dom";
import maplibregl from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";
import { ListingFilters, listingParams, sourceName } from "../api";

const STYLE_URL = "https://tiles.openfreemap.org/styles/positron";
const QUEBEC_CENTER: [number, number] = [-72.5, 46.4];

function geojsonUrl(f: ListingFilters): string {
  return `/api/listings.geojson?${listingParams(f)}`;
}

function popupHTML(p: Record<string, unknown>): string {
  const prix = p.price != null
    ? `${Number(p.price).toLocaleString("fr-CA", { maximumFractionDigits: 0 })} $`
    : (p.price_label as string) || "Prix sur demande";
  const img = p.image
    ? `<img src="${p.image}" alt="" loading="lazy"/>`
    : `<div class="mv-noimg">🏠</div>`;
  const meta = [
    p.property_type,
    p.bedrooms != null ? `${p.bedrooms} ch.` : "",
    p.bathrooms != null ? `${p.bathrooms} sdb` : "",
  ].filter(Boolean).join(" · ");
  return `
    <div class="mv-pop">
      ${img}
      <div class="mv-pop-body">
        <div class="mv-pop-price">${prix}</div>
        <div class="mv-pop-title">${p.address ?? p.title ?? ""}</div>
        <div class="mv-pop-meta">${meta}</div>
        <div class="mv-pop-src">${sourceName(String(p.source ?? ""))}</div>
        <a class="mv-pop-cta" href="/propriete/${encodeURIComponent(String(p.uid))}">Voir la fiche →</a>
      </div>
    </div>`;
}

export default function MapView({ filters }: { filters: ListingFilters }) {
  const div = useRef<HTMLDivElement>(null);
  const mapRef = useRef<maplibregl.Map | null>(null);
  const loadedRef = useRef(false);
  const navigate = useNavigate();

  useEffect(() => {
    if (!div.current || mapRef.current) return;
    const map = new maplibregl.Map({
      container: div.current,
      style: STYLE_URL,
      center: QUEBEC_CENTER,
      zoom: 6,
      attributionControl: { compact: true },
    });
    mapRef.current = map;
    map.addControl(new maplibregl.NavigationControl({ showCompass: false }), "top-right");
    map.addControl(new maplibregl.GeolocateControl({ trackUserLocation: false }), "top-right");
    map.touchZoomRotate.disableRotation();

    map.on("load", () => {
      map.addSource("props", {
        type: "geojson",
        data: { type: "FeatureCollection", features: [] },
        cluster: true,
        clusterMaxZoom: 15,
        clusterRadius: 46,
      });
      map.addLayer({
        id: "clusters", type: "circle", source: "props",
        filter: ["has", "point_count"],
        paint: {
          "circle-color": "#141814",
          "circle-radius": ["step", ["get", "point_count"], 15, 10, 19, 50, 24, 200, 30],
          "circle-stroke-width": 3,
          "circle-stroke-color": "#d9f26b",
        },
      });
      map.addLayer({
        id: "cluster-count", type: "symbol", source: "props",
        filter: ["has", "point_count"],
        layout: {
          "text-field": ["get", "point_count_abbreviated"],
          "text-font": ["Noto Sans Bold"],
          "text-size": 13,
        },
        paint: { "text-color": "#d9f26b" },
      });
      map.addLayer({
        id: "point", type: "circle", source: "props",
        filter: ["!", ["has", "point_count"]],
        paint: {
          "circle-color": "#1c5c41",
          "circle-radius": 5,
          "circle-stroke-width": 1.5,
          "circle-stroke-color": "#f5f3ee",
        },
      });
      map.addLayer({
        id: "point-price", type: "symbol", source: "props",
        filter: ["!", ["has", "point_count"]],
        layout: {
          "text-field": [
            "case",
            ["to-boolean", ["get", "price"]],
            ["concat", ["number-format", ["get", "price"], { locale: "fr-CA", "max-fraction-digits": 0 }], " $"],
            "•",
          ],
          "text-font": ["Noto Sans Bold"],
          "text-size": 12,
          "text-offset": [0, -1.1],
          "text-allow-overlap": false,
          "text-optional": true,
        } as maplibregl.SymbolLayerSpecification["layout"],
        paint: {
          "text-color": "#141814",
          "text-halo-color": "#d9f26b",
          "text-halo-width": 2,
        },
      });

      map.on("click", "clusters", async (e: maplibregl.MapLayerMouseEvent) => {
        const f = map.queryRenderedFeatures(e.point, { layers: ["clusters"] })[0];
        const src = map.getSource("props") as maplibregl.GeoJSONSource;
        const zoom = await src.getClusterExpansionZoom(f.properties!.cluster_id);
        map.easeTo({ center: (f.geometry as GeoJSON.Point).coordinates as [number, number], zoom });
      });
      const openPopup = (e: maplibregl.MapLayerMouseEvent) => {
        const f = e.features?.[0];
        if (!f) return;
        const coords = (f.geometry as GeoJSON.Point).coordinates.slice() as [number, number];
        const pop = new maplibregl.Popup({ offset: 14, maxWidth: "290px", closeButton: true })
          .setLngLat(coords).setHTML(popupHTML(f.properties as Record<string, unknown>)).addTo(map);
        pop.getElement().querySelector(".mv-pop-cta")?.addEventListener("click", (ev: Event) => {
          ev.preventDefault();
          navigate(`/propriete/${encodeURIComponent(String((f.properties as any).uid))}`);
        });
      };
      map.on("click", "point", openPopup);
      map.on("click", "point-price", openPopup);
      for (const layer of ["clusters", "point", "point-price"]) {
        map.on("mouseenter", layer, () => { map.getCanvas().style.cursor = "pointer"; });
        map.on("mouseleave", layer, () => { map.getCanvas().style.cursor = ""; });
      }
      loadedRef.current = true;
    });

    return () => { map.remove(); mapRef.current = null; loadedRef.current = false; };
  }, [navigate]);

  useEffect(() => {
    const map = mapRef.current;
    if (!map) return;
    let cancelled = false;
    const apply = async () => {
      try {
        const res = await fetch(geojsonUrl(filters));
        const data = (await res.json()) as GeoJSON.FeatureCollection;
        if (cancelled || !mapRef.current) return;
        (map.getSource("props") as maplibregl.GeoJSONSource | undefined)?.setData(data);
        if (data.features.length > 0) {
          const b = new maplibregl.LngLatBounds();
          for (const f of data.features)
            b.extend((f.geometry as GeoJSON.Point).coordinates as [number, number]);
          map.fitBounds(b, { padding: 56, maxZoom: 14, duration: 500 });
        }
      } catch { /* réseau : la carte garde ses données précédentes */ }
    };
    if (loadedRef.current) apply();
    else map.once("load", () => apply());
    return () => { cancelled = true; };
  }, [filters]);

  return <div ref={div} className="mapview" role="application" aria-label="Carte des propriétés" />;
}
