import { useEffect, useRef, useState, useMemo } from "preact/hooks";
import type { StandaloneMap, MapPlace } from "../lib/types";

declare const L: any;

function haversineKm(lat1: number, lng1: number, lat2: number, lng2: number): number {
  const R = 6371;
  const dLat = (lat2 - lat1) * Math.PI / 180;
  const dLng = (lng2 - lng1) * Math.PI / 180;
  const a = Math.sin(dLat/2)**2 + Math.cos(lat1*Math.PI/180)*Math.cos(lat2*Math.PI/180)*Math.sin(dLng/2)**2;
  return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
}

function fmtDist(km: number): string {
  return km < 1 ? `${Math.round(km*1000)}m` : `${km.toFixed(1)}km`;
}

const LEAFLET_CSS = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css";
const LEAFLET_JS = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js";

function loadLeaflet(): Promise<void> {
  if (typeof L !== "undefined") return Promise.resolve();

  return new Promise((resolve, reject) => {
    if (!document.querySelector(`link[href="${LEAFLET_CSS}"]`)) {
      const link = document.createElement("link");
      link.rel = "stylesheet";
      link.href = LEAFLET_CSS;
      document.head.appendChild(link);
    }

    if (document.querySelector(`script[src="${LEAFLET_JS}"]`)) {
      const check = setInterval(() => {
        if (typeof L !== "undefined") { clearInterval(check); resolve(); }
      }, 50);
      return;
    }

    const script = document.createElement("script");
    script.src = LEAFLET_JS;
    script.onload = () => resolve();
    script.onerror = () => reject(new Error("Failed to load Leaflet"));
    document.head.appendChild(script);
  });
}

function PlaceCard({
  place,
  index,
  highlighted,
  onSelect,
  distKm,
}: {
  place: MapPlace;
  index: number;
  highlighted: boolean;
  onSelect: () => void;
  distKm?: number;
}) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (highlighted && ref.current) {
      ref.current.scrollIntoView({ behavior: "smooth", block: "nearest" });
    }
  }, [highlighted]);

  return (
    <div
      ref={ref}
      class={`place-card standalone-place-card${highlighted ? " standalone-place-highlighted" : ""}`}
      onClick={onSelect}
    >
      <div class="place-card-top">
        <div class="place-card-name">{place.name}</div>
        <div class="place-card-badges">
          {distKm !== undefined && (
            <span class="standalone-dist-badge">{fmtDist(distKm)}</span>
          )}
          {place.ebt && (
            <span class="standalone-ebt-badge">{place.ebt}</span>
          )}
        </div>
      </div>
      {place.city && (
        <div class="standalone-place-city">{place.city}</div>
      )}
      <div class="place-card-detail">
        {place.address && (
          <div class="place-detail-row">
            <span class="place-detail-label">Address</span>
            <span class="place-detail-val">{place.address}</span>
          </div>
        )}
        {place.hours && (
          <div class="place-detail-row">
            <span class="place-detail-label">Hours</span>
            <span class="place-detail-val">{place.hours}</span>
          </div>
        )}
        {place.phone && (
          <div class="place-detail-row">
            <span class="place-detail-label">Phone</span>
            <span class="place-detail-val">
              <a class="place-phone-link" href={`tel:${place.phone}`}>{place.phone}</a>
            </span>
          </div>
        )}
        {place.website && (
          <div class="place-detail-row">
            <span class="place-detail-label">Web</span>
            <span class="place-detail-val">
              <a
                class="place-web-link"
                href={place.website}
                target="_blank"
                rel="noopener noreferrer"
                onClick={e => e.stopPropagation()}
              >
                Visit site
              </a>
            </span>
          </div>
        )}
      </div>
    </div>
  );
}

export function MapView({
  standaloneMap,
  onBack,
}: {
  standaloneMap: StandaloneMap;
  onBack: () => void;
}) {
  const mapRef = useRef<HTMLDivElement>(null);
  const mapInstance = useRef<any>(null);
  const markersRef = useRef<any[]>([]);
  const userMarker = useRef<any>(null);
  const [ready, setReady] = useState(false);
  const [mapError, setMapError] = useState<string | null>(null);
  const [query, setQuery] = useState("");
  const [highlightedIdx, setHighlightedIdx] = useState<number | null>(null);
  const [userLocation, setUserLocation] = useState<{ lat: number; lng: number } | null>(null);

  const places = standaloneMap.places;

  const placesWithDist = useMemo(() => {
    return places.map(p => ({
      place: p,
      distKm: userLocation ? haversineKm(userLocation.lat, userLocation.lng, p.lat, p.lng) : undefined,
    }));
  }, [places, userLocation]);

  const sorted = useMemo(() => {
    if (!userLocation) return placesWithDist;
    return [...placesWithDist].sort((a, b) => (a.distKm ?? 0) - (b.distKm ?? 0));
  }, [placesWithDist, userLocation]);

  const filtered = query.trim()
    ? sorted.filter(({ place }) => {
        const q = query.toLowerCase();
        return (
          place.name.toLowerCase().includes(q) ||
          (place.city && place.city.toLowerCase().includes(q))
        );
      })
    : sorted;

  useEffect(() => {
    loadLeaflet()
      .then(() => setReady(true))
      .catch(e => setMapError(e.message));
  }, []);

  // Auto-acquire location on mount
  useEffect(() => {
    if (!navigator.geolocation) return;
    navigator.geolocation.getCurrentPosition(pos => {
      setUserLocation({ lat: pos.coords.latitude, lng: pos.coords.longitude });
    }, () => {});
  }, []);

  useEffect(() => {
    if (!ready || !mapRef.current || mapInstance.current) return;

    const map = L.map(mapRef.current, {
      zoomControl: true,
      scrollWheelZoom: true,
    });

    L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
      attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap</a>',
      maxZoom: 18,
    }).addTo(map);

    const bounds: [number, number][] = [];
    const markers: any[] = [];

    places.forEach((place, i) => {
      const marker = L.circleMarker([place.lat, place.lng], {
        radius: 7,
        fillColor: "#3b82f6",
        color: "#fff",
        weight: 2,
        opacity: 1,
        fillOpacity: 0.85,
      }).addTo(map);

      const popupLines = [
        `<strong>${place.name}</strong>`,
        place.address ? `<span style="font-size:11px;color:#888">${place.address}</span>` : "",
        place.hours ? `<span style="font-size:11px;color:#888">${place.hours}</span>` : "",
        place.phone ? `<a href="tel:${place.phone}" style="color:var(--gold,#b49a6a);font-size:11px">${place.phone}</a>` : "",
        place.ebt ? `<span style="font-size:10px;font-weight:700;background:#b49a6a;color:#fff;padding:1px 6px;border-radius:4px">${place.ebt} EBT</span>` : "",
      ].filter(Boolean).join("<br>");

      marker.bindPopup(popupLines, { maxWidth: 220, className: "map-popup" });

      marker.on("click", () => {
        setHighlightedIdx(i);
      });

      markers.push(marker);
      bounds.push([place.lat, place.lng]);
    });

    markersRef.current = markers;

    if (bounds.length > 0) {
      map.fitBounds(L.latLngBounds(bounds), { padding: [30, 30] });
    } else {
      map.setView([36.7, -119.7], 6);
    }

    mapInstance.current = map;

    return () => {
      map.remove();
      mapInstance.current = null;
      markersRef.current = [];
    };
  }, [ready]);

  const selectPlace = (globalIdx: number) => {
    setHighlightedIdx(globalIdx);
    const marker = markersRef.current[globalIdx];
    const place = places[globalIdx];
    if (mapInstance.current && marker) {
      mapInstance.current.setView([place.lat, place.lng], Math.max(mapInstance.current.getZoom(), 13));
      marker.openPopup();
    }
  };

  const centerOnMe = () => {
    if (!navigator.geolocation) return;
    navigator.geolocation.getCurrentPosition(pos => {
      const lat = pos.coords.latitude;
      const lng = pos.coords.longitude;
      setUserLocation({ lat, lng });
      if (mapInstance.current) {
        mapInstance.current.setView([lat, lng], 12);
      }
    });
  };

  // Sync user marker whenever location updates
  useEffect(() => {
    if (!userLocation || !mapInstance.current) return;
    const { lat, lng } = userLocation;
    if (!userMarker.current) {
      userMarker.current = L.circleMarker([lat, lng], {
        radius: 8,
        fillColor: "#3b82f6",
        color: "#fff",
        weight: 3,
        opacity: 1,
        fillOpacity: 1,
      }).addTo(mapInstance.current);
    } else {
      userMarker.current.setLatLng([lat, lng]);
    }
  }, [userLocation, ready]);


  return (
    <div class="standalone-map-view">
      {/* Header */}
      <div class="trip-view">
        <div class="trip-back-row">
          <button class="trip-back" onClick={onBack}>&#8592; Maps</button>
        </div>
        <div class="trip-header">
          <h1 class="trip-title">{standaloneMap.title}</h1>
          {standaloneMap.subtitle && (
            <div class="trip-subtitle">{standaloneMap.subtitle}</div>
          )}
        </div>

        {/* Map */}
        <div class="standalone-map-container" ref={mapRef}>
          {!ready && !mapError && <div class="map-loading">Loading map...</div>}
          {mapError && <div class="map-error">Failed to load map: {mapError}</div>}
        </div>

        {/* Map controls */}
        <div class="map-controls">
          <button class="map-btn" onClick={centerOnMe} title="My location">
            <span class="map-btn-dot" />My Location
          </button>
          {places.length > 0 && (
            <button
              class="map-btn"
              onClick={() => {
                if (!mapInstance.current || places.length === 0) return;
                const bounds = places.map(p => [p.lat, p.lng] as [number, number]);
                mapInstance.current.fitBounds(L.latLngBounds(bounds), { padding: [30, 30] });
              }}
            >
              All Places
            </button>
          )}
        </div>

        {/* Search */}
        {places.length > 0 && (
          <div class="standalone-search-bar">
            <input
              class="standalone-search-input"
              type="search"
              placeholder={`Search ${places.length} places…`}
              value={query}
              onInput={e => setQuery((e.target as HTMLInputElement).value)}
            />
          </div>
        )}

        {/* Place list */}
        {places.length === 0 ? (
          <div class="empty-state">No places in this map yet.</div>
        ) : (
          <div class="standalone-place-list">
            {filtered.length === 0 && query && (
              <div class="empty-state">No places match "{query}".</div>
            )}
            {filtered.map(({ place, distKm }) => {
              const globalIdx = places.indexOf(place);
              return (
                <PlaceCard
                  key={globalIdx}
                  place={place}
                  index={globalIdx}
                  highlighted={highlightedIdx === globalIdx}
                  onSelect={() => selectPlace(globalIdx)}
                  distKm={distKm}
                />
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
}
