"use client";

import React, {
  CSSProperties,
  createContext,
  memo,
  useContext,
  useEffect,
  useRef,
  useState,
} from "react";
import { createPortal } from "react-dom";
import maplibregl, { Map as MapLibreMap, Marker as MapLibreMarker } from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";
import { defaultLocation } from "@/config/global";
import { getMapIrKey } from "@/config/runtime";
import { IconButton } from "@/components/icon-button";
import NavigationIcon from "@/assets/icons/navigation";
import { LoadingCard } from "@/components/loading";
import { useSettings } from "@/hook/use-settings";
import PlusIcon from "@/assets/icons/plus";
import MinusIcon from "@/assets/icons/minus";
import { mapIrStyleUrl, mapIrTransformRequest, ensureMapRtlTextPlugin, isValidMapIrKey } from "@/lib/map-ir";

type LatLng = { lat: number; lng: number };

interface MapProps extends React.PropsWithChildren {
  center?: LatLng;
  zoom?: number;
  containerStyles: CSSProperties;
  options?: Record<string, unknown>;
  onClick?: (e: { latLng: { lat: () => number; lng: () => number } | null }) => void;
  onLoad?: (map: MapLibreMap) => void;
  onCenterChange?: () => void;
  findMyLocation?: boolean;
}

const MapContext = createContext<MapLibreMap | null>(null);

export const useMapInstance = () => useContext(MapContext);

export const Map: React.FC<MapProps> = memo(
  ({
    center,
    containerStyles,
    children,
    zoom = 9,
    onClick,
    onLoad,
    onCenterChange,
    findMyLocation = true,
    options,
  }) => {
    const { settings } = useSettings();
    const apiKey = [
      settings?.map_ir_key,
      settings?.mapir_key,
      settings?.google_map_key,
      getMapIrKey(),
      process.env.NEXT_PUBLIC_MAP_IR_KEY,
      process.env.NEXT_PUBLIC_GOOGLE_MAPS_KEY,
    ]
      .map((k) => String(k || "").trim())
      .find((k) => isValidMapIrKey(k)) || "";

    const optionsCenter = options?.center as LatLng | undefined;
    const propCenter = center || optionsCenter;

    let defaultCenter = defaultLocation;
    if (settings?.location) {
      const locationArr = settings.location.split(",");
      defaultCenter = { lat: Number(locationArr[0]), lng: Number(locationArr[1]) };
    }
    if (propCenter) defaultCenter = propCenter;

    const [currentCenter, setCurrentCenter] = useState(defaultCenter);
    const [currentZoom, setCurrentZoom] = useState(zoom);
    const [mapReady, setMapReady] = useState(false);
    const containerRef = useRef<HTMLDivElement>(null);
    const mapRef = useRef<MapLibreMap | null>(null);

    // وقتی از autocomplete / فرم مختصات عوض شد، نقشه هم جابه‌جا شود
    useEffect(() => {
      if (
        propCenter &&
        Number.isFinite(propCenter.lat) &&
        Number.isFinite(propCenter.lng) &&
        (propCenter.lat !== currentCenter.lat || propCenter.lng !== currentCenter.lng)
      ) {
        setCurrentCenter(propCenter);
        setCurrentZoom((z) => (z < 14 ? 15 : z));
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [propCenter?.lat, propCenter?.lng]);

    useEffect(() => {
      if (!isValidMapIrKey(apiKey) || !containerRef.current || mapRef.current) return;
      let cancelled = false;

      (async () => {
        await ensureMapRtlTextPlugin();
        if (cancelled || !containerRef.current || mapRef.current) return;

        const map = new maplibregl.Map({
          container: containerRef.current,
          style: mapIrStyleUrl(apiKey),
          center: [currentCenter.lng, currentCenter.lat],
          zoom: currentZoom,
          localIdeographFontFamily: "'Vazirmatn', 'Tahoma', sans-serif",
          transformRequest: mapIrTransformRequest(apiKey),
        });
        mapRef.current = map;

        map.on("load", () => {
          setMapReady(true);
          onLoad?.(map);
        });
        map.on("click", (e) => {
          onClick?.({
            latLng: {
              lat: () => e.lngLat.lat,
              lng: () => e.lngLat.lng,
            },
          });
        });
        map.on("moveend", () => onCenterChange?.());
      })();

      return () => {
        cancelled = true;
        mapRef.current?.remove();
        mapRef.current = null;
        setMapReady(false);
      };
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [apiKey]);

    useEffect(() => {
      mapRef.current?.setCenter([currentCenter.lng, currentCenter.lat]);
    }, [currentCenter.lat, currentCenter.lng]);

    useEffect(() => {
      mapRef.current?.setZoom(currentZoom);
    }, [currentZoom]);

    const getUserCurrentLocation = () => {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition((position) => {
          setCurrentCenter({
            lat: position.coords.latitude,
            lng: position.coords.longitude,
          });
          setCurrentZoom(14);
        });
      }
    };

    if (!isValidMapIrKey(apiKey)) {
      return (
        <div
          style={containerStyles}
          className="flex items-center justify-center bg-gray-100 text-gray-500 text-center p-4"
        >
          کلید نقشه مپ (Map.ir) تنظیم نشده است
        </div>
      );
    }

    return (
      <div style={{ ...containerStyles, position: "relative" }} className="!font-sans">
        <div ref={containerRef} style={{ width: "100%", height: "100%" }} />
        {!mapReady && (
          <div className="absolute inset-0 flex items-center justify-center bg-white/60">
            <LoadingCard />
          </div>
        )}
        <MapContext.Provider value={mapRef.current}>{mapReady ? children : null}</MapContext.Provider>
        {findMyLocation && (
          <div className="absolute bottom-5 right-5 flex flex-col gap-3 z-10">
            <div className="flex flex-col bg-white rounded-[5px] items-center">
              <IconButton
                onClick={() => setCurrentZoom((z) => (z < 18 ? z + 1 : z))}
                type="button"
                size="large"
              >
                <PlusIcon />
              </IconButton>
              <div className="h-px bg-footerBg w-10/12 bg-opacity-20" />
              <IconButton
                onClick={() => setCurrentZoom((z) => (z > 2 ? z - 1 : z))}
                type="button"
                size="large"
              >
                <MinusIcon />
              </IconButton>
            </div>
            <IconButton type="button" onClick={getUserCurrentLocation} size="large" color="white">
              <NavigationIcon />
            </IconButton>
          </div>
        )}
      </div>
    );
  }
);

/** جایگزین MarkerF گوگل — children با portal داخل المان مارکر */
export function MarkerF({
  position,
  children,
  icon,
  onClick,
}: {
  position: LatLng;
  children?: React.ReactNode;
  icon?: string;
  onClick?: () => void;
}) {
  const map = useMapInstance();
  const markerRef = useRef<MapLibreMarker | null>(null);
  const elRef = useRef<HTMLDivElement | null>(null);
  const onClickRef = useRef(onClick);
  onClickRef.current = onClick;
  const [, setTick] = useState(0);

  useEffect(() => {
    if (!map || !position) return;
    const el = document.createElement("div");
    el.style.cursor = onClickRef.current ? "pointer" : "default";
    elRef.current = el;
    if (!children) {
      if (icon) {
        el.style.width = "32px";
        el.style.height = "32px";
        el.innerHTML = `<img src="${icon}" alt="" style="width:100%;height:100%;object-fit:contain;pointer-events:none" />`;
      } else {
        el.style.width = "22px";
        el.style.height = "22px";
        el.style.borderRadius = "50%";
        el.style.background = "#e11d48";
        el.style.border = "2px solid #fff";
        el.style.boxShadow = "0 1px 4px rgba(0,0,0,.35)";
      }
    }
    const handleClick = () => onClickRef.current?.();
    el.addEventListener("click", handleClick);
    const marker = new maplibregl.Marker({ element: el })
      .setLngLat([position.lng, position.lat])
      .addTo(map);
    markerRef.current = marker;
    setTick((t) => t + 1);
    return () => {
      el.removeEventListener("click", handleClick);
      marker.remove();
      markerRef.current = null;
      elRef.current = null;
    };
  }, [map, position.lat, position.lng, icon, children]);

  useEffect(() => {
    markerRef.current?.setLngLat([position.lng, position.lat]);
  }, [position.lat, position.lng]);

  if (children && elRef.current) {
    return createPortal(children, elRef.current);
  }
  return null;
}

/** سازگاری با OverlayViewF گوگل */
export function OverlayViewF({
  position,
  children,
}: {
  position: LatLng;
  children?: React.ReactNode;
  mapPaneName?: string;
}) {
  return <MarkerF position={position}>{children}</MarkerF>;
}

export const OverlayView = { OVERLAY_MOUSE_TARGET: "overlayMouseTarget", MAP_PANE: "mapPane" };

Map.displayName = "Map";
