"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
  APIProvider,
  Map,
  AdvancedMarker,
  InfoWindow,
  useMap,
} from "@vis.gl/react-google-maps";
import Supercluster from "supercluster";
import type { Restaurant } from "@/lib/api";
import { getCuisineIcon } from "@/lib/cuisine-icons";
import Icon from "@/components/Icon";

const SEOUL_CENTER = { lat: 37.5665, lng: 126.978 };
const API_KEY = process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY || "";

// Channel color palette
const CHANNEL_COLORS = [
  { bg: "#fff7ed", text: "#78350f", border: "#f59e0b", arrow: "#f59e0b" }, // amber (default)
  { bg: "#eff6ff", text: "#1e3a5f", border: "#3b82f6", arrow: "#3b82f6" }, // blue
  { bg: "#f0fdf4", text: "#14532d", border: "#22c55e", arrow: "#22c55e" }, // green
  { bg: "#fdf2f8", text: "#831843", border: "#ec4899", arrow: "#ec4899" }, // pink
  { bg: "#faf5ff", text: "#581c87", border: "#a855f7", arrow: "#a855f7" }, // purple
  { bg: "#fff1f2", text: "#7f1d1d", border: "#ef4444", arrow: "#ef4444" }, // red
  { bg: "#f0fdfa", text: "#134e4a", border: "#14b8a6", arrow: "#14b8a6" }, // teal
  { bg: "#fefce8", text: "#713f12", border: "#eab308", arrow: "#eab308" }, // yellow
];

function getChannelColorMap(restaurants: Restaurant[]) {
  const channels = new Set<string>();
  restaurants.forEach((r) => r.channels?.forEach((ch) => channels.add(ch)));
  const map: Record<string, typeof CHANNEL_COLORS[0]> = {};
  let i = 0;
  for (const ch of channels) {
    map[ch] = CHANNEL_COLORS[i % CHANNEL_COLORS.length];
    i++;
  }
  return map;
}

import type { MapBounds, FlyTo, MapViewProps } from "@/components/MapView.types";

type RestaurantProps = { restaurant: Restaurant };
type RestaurantFeature = Supercluster.PointFeature<RestaurantProps>;

function useSupercluster(restaurants: Restaurant[]) {
  // #278 — indexRef 제거 (set만 되고 read 없는 dead code)
  const points: RestaurantFeature[] = useMemo(
    () =>
      restaurants.map((r) => ({
        type: "Feature" as const,
        geometry: { type: "Point" as const, coordinates: [r.longitude, r.latitude] },
        properties: { restaurant: r },
      })),
    [restaurants]
  );

  const index = useMemo(() => {
    const sc = new Supercluster<{ restaurant: Restaurant }>({
      radius: 60,
      maxZoom: 16,
      minPoints: 2,
    });
    sc.load(points);
    return sc;
  }, [points]);

  const getClusters = useCallback(
    (bounds: MapBounds, zoom: number) => {
      return index.getClusters(
        [bounds.west, bounds.south, bounds.east, bounds.north],
        Math.floor(zoom)
      );
    },
    [index]
  );

  const getExpansionZoom = useCallback(
    (clusterId: number): number => {
      try {
        return index.getClusterExpansionZoom(clusterId);
      } catch {
        return 17;
      }
    },
    [index]
  );

  return { getClusters, getExpansionZoom, index };
}

function getClusterSize(count: number): number {
  if (count < 10) return 36;
  if (count < 50) return 42;
  if (count < 100) return 48;
  return 54;
}

function MapContent({ restaurants, selected, onSelectRestaurant, flyTo, activeChannel }: Omit<MapViewProps, "onMyLocation" | "onBoundsChanged">) {
  const map = useMap();
  const [infoTarget, setInfoTarget] = useState<Restaurant | null>(null);
  const [zoom, setZoom] = useState(13);
  const [bounds, setBounds] = useState<MapBounds | null>(null);
  const channelColors = useMemo(() => getChannelColorMap(restaurants), [restaurants]);
  const { getClusters, getExpansionZoom } = useSupercluster(restaurants);

  // #278 — restaurantMap 제거 (빌드만 되고 렌더에서 사용 안 됨, dead code)

  const clusters = useMemo(() => {
    if (!bounds) return [];
    return getClusters(bounds, zoom);
  }, [bounds, zoom, getClusters]);

  const handleMarkerClick = useCallback(
    (r: Restaurant) => {
      setInfoTarget(r);
      onSelectRestaurant?.(r);
    },
    [onSelectRestaurant]
  );

  const handleClusterClick = useCallback(
    (clusterId: number, lng: number, lat: number) => {
      if (!map) return;
      const expansionZoom = Math.min(getExpansionZoom(clusterId), 18);
      map.panTo({ lat, lng });
      map.setZoom(expansionZoom);
    },
    [map, getExpansionZoom]
  );

  // Track camera changes for clustering
  useEffect(() => {
    if (!map) return;
    const listener = map.addListener("idle", () => {
      const b = map.getBounds();
      const z = map.getZoom();
      if (b && z != null) {
        const ne = b.getNorthEast();
        const sw = b.getSouthWest();
        setBounds({ north: ne.lat(), south: sw.lat(), east: ne.lng(), west: sw.lng() });
        setZoom(z);
      }
    });
    // Trigger initial bounds
    const b = map.getBounds();
    const z = map.getZoom();
    if (b && z != null) {
      const ne = b.getNorthEast();
      const sw = b.getSouthWest();
      setBounds({ north: ne.lat(), south: sw.lat(), east: ne.lng(), west: sw.lng() });
      setZoom(z);
    }
    return () => google.maps.event.removeListener(listener);
  }, [map]);

  // Fly to a specific location (region filter)
  useEffect(() => {
    if (!map || !flyTo) return;
    map.panTo({ lat: flyTo.lat, lng: flyTo.lng });
    if (flyTo.zoom) map.setZoom(flyTo.zoom);
  }, [map, flyTo]);

  // Pan and zoom to selected restaurant — 현재 줌이 16 이상이면 유지(클러스터 expansion 후 재묶임 방지)
  useEffect(() => {
    if (!map || !selected) return;
    map.panTo({ lat: selected.latitude, lng: selected.longitude });
    const currentZoom = map.getZoom() ?? 13;
    if (currentZoom < 16) map.setZoom(16);
    setInfoTarget(selected);
  }, [map, selected]);

  return (
    <>
      {clusters.map((feature) => {
        const [lng, lat] = feature.geometry.coordinates;
        const isCluster = feature.properties && "cluster" in feature.properties && feature.properties.cluster;

        if (isCluster) {
          const { cluster_id, point_count } = feature.properties as Supercluster.ClusterProperties;
          const size = getClusterSize(point_count);
          return (
            <AdvancedMarker
              key={`cluster-${cluster_id}`}
              position={{ lat, lng }}
              onClick={() => handleClusterClick(cluster_id, lng, lat)}
              zIndex={100}
            >
              <div
                role="button"
                aria-label={`${point_count}개 식당이 모인 클러스터, 클릭하면 확대됩니다`}
                style={{
                  width: size,
                  height: size,
                  borderRadius: "50%",
                  background: "linear-gradient(135deg, #E8720C 0%, #f59e0b 100%)",
                  border: "3px solid #fff",
                  boxShadow: "0 2px 8px rgba(0,0,0,0.25)",
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "center",
                  color: "#fff",
                  fontSize: size > 42 ? 15 : 13,
                  fontWeight: 700,
                  cursor: "pointer",
                  transition: "transform 0.2s ease",
                }}
              >
                {point_count}
              </div>
            </AdvancedMarker>
          );
        }

        // Individual marker
        const r = (feature.properties as { restaurant: Restaurant }).restaurant;
        const isSelected = selected?.id === r.id;
        const isClosed = r.business_status === "CLOSED_PERMANENTLY";
        const chKey = activeChannel && r.channels?.includes(activeChannel) ? activeChannel : r.channels?.[0];
        const chColor = chKey ? channelColors[chKey] : CHANNEL_COLORS[0];
        const c = chColor || CHANNEL_COLORS[0];
        return (
          <AdvancedMarker
            key={r.id}
            position={{ lat: r.latitude, lng: r.longitude }}
            onClick={() => handleMarkerClick(r)}
            zIndex={isSelected ? 1000 : 1}
          >
            <div
              role="button"
              aria-label={`${r.name}${isClosed ? ' (폐업)' : ''}, 클릭하면 상세 정보가 표시됩니다`}
              style={{ display: "flex", flexDirection: "column", alignItems: "center", transition: "transform 0.2s ease", transform: isSelected ? "scale(1.15)" : "scale(1)", opacity: isClosed ? 0.5 : 1 }}>
              <div
                style={{
                  padding: "4px 8px",
                  backgroundColor: isSelected ? "#2563eb" : isClosed ? "#f3f4f6" : c.bg,
                  color: isSelected ? "#fff" : isClosed ? "#9ca3af" : c.text,
                  fontSize: 12,
                  fontWeight: 600,
                  borderRadius: 6,
                  border: isSelected ? "2px solid #1d4ed8" : `1.5px solid ${c.border}`,
                  boxShadow: isSelected
                    ? "0 2px 8px rgba(37,99,235,0.4)"
                    : `0 1px 4px ${c.border}40`,
                  whiteSpace: "nowrap",
                  maxWidth: 120,
                  overflow: "hidden",
                  textOverflow: "ellipsis",
                  textDecoration: isClosed ? "line-through" : "none",
                }}
              >
                <span className="material-symbols-rounded" style={{ fontSize: 14, width: 14, height: 14, overflow: "hidden", display: "inline-flex", alignItems: "center", justifyContent: "center", marginRight: 3, verticalAlign: "middle", color: "#E8720C" }}>{getCuisineIcon(r.cuisine_type)}</span>
                {r.name}
              </div>
              <div
                style={{
                  width: 0,
                  height: 0,
                  borderLeft: "6px solid transparent",
                  borderRight: "6px solid transparent",
                  borderTop: isSelected ? "6px solid #1d4ed8" : `6px solid ${c.arrow}`,
                  marginTop: -1,
                }}
              />
            </div>
          </AdvancedMarker>
        );
      })}

      {infoTarget && (
        <InfoWindow
          position={{ lat: infoTarget.latitude, lng: infoTarget.longitude }}
          onCloseClick={() => setInfoTarget(null)}
        >
          <div style={{ backgroundColor: "#ffffff", color: "#171717", colorScheme: "light" }} className="max-w-xs p-1">
            <div className="flex items-center gap-2">
              <h3 className="font-bold text-base" style={{ color: "#171717" }}><span className="material-symbols-rounded" style={{ fontSize: 18, width: 18, height: 18, overflow: "hidden", display: "inline-flex", alignItems: "center", justifyContent: "center", verticalAlign: "middle", color: "#E8720C", marginRight: 4 }}>{getCuisineIcon(infoTarget.cuisine_type)}</span>{infoTarget.name}</h3>
              {infoTarget.business_status === "CLOSED_PERMANENTLY" && (
                <span className="px-1.5 py-0.5 bg-red-100 text-red-700 rounded text-[10px] font-semibold">폐업</span>
              )}
              {infoTarget.business_status === "CLOSED_TEMPORARILY" && (
                <span className="px-1.5 py-0.5 bg-yellow-100 text-yellow-700 rounded text-[10px] font-semibold">임시휴업</span>
              )}
            </div>
            {infoTarget.rating && (
              <p className="text-xs mt-0.5">
                <span className="text-yellow-500">★</span> {infoTarget.rating}
                {infoTarget.rating_count && (
                  <span className="text-gray-400 ml-1">({infoTarget.rating_count.toLocaleString()})</span>
                )}
              </p>
            )}
            {infoTarget.cuisine_type && (
              <p className="text-xs text-gray-500">{infoTarget.cuisine_type}</p>
            )}
            {infoTarget.address && (
              <p className="text-[11px] text-gray-400 mt-1">{infoTarget.address}</p>
            )}
            {infoTarget.price_range && (
              <p className="text-[11px] text-gray-400">{infoTarget.price_range}</p>
            )}
            {infoTarget.phone && (
              <p className="text-[11px] text-gray-400">{infoTarget.phone}</p>
            )}
            <button
              onClick={() => onSelectRestaurant?.(infoTarget)}
              className="mt-2 text-sm text-blue-600 hover:underline"
            >
              상세 보기
            </button>
          </div>
        </InfoWindow>
      )}
    </>
  );
}

export default function GoogleMapView({ restaurants, selected, onSelectRestaurant, onBoundsChanged, flyTo, onMyLocation, activeChannel }: MapViewProps) {
  const channelColors = useMemo(() => getChannelColorMap(restaurants), [restaurants]);
  const channelNames = useMemo(() => {
    const names = Object.keys(channelColors);
    if (activeChannel) return names.filter((n) => n === activeChannel);
    return names;
  }, [channelColors, activeChannel]);
  const boundsTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const handleCameraChanged = useCallback((ev: { detail: { bounds: { north: number; south: number; east: number; west: number } } }) => {
    if (!onBoundsChanged) return;
    if (boundsTimerRef.current) clearTimeout(boundsTimerRef.current);
    boundsTimerRef.current = setTimeout(() => {
      const { north, south, east, west } = ev.detail.bounds;
      onBoundsChanged({ north, south, east, west });
    }, 150);
  }, [onBoundsChanged]);

  // #278 — 언마운트 시 디바운스 타이머 정리 (메모리 누수 + unmounted setState 경고 방지)
  useEffect(() => {
    return () => {
      if (boundsTimerRef.current) clearTimeout(boundsTimerRef.current);
    };
  }, []);

  return (
    <APIProvider apiKey={API_KEY}>
      <Map
        defaultCenter={SEOUL_CENTER}
        defaultZoom={13}
        mapId="tasteby-map"
        className="h-full w-full"
        colorScheme="LIGHT"
        mapTypeControl={false}
        fullscreenControl={false}
        onCameraChanged={handleCameraChanged}
      >
        <MapContent
          restaurants={restaurants}
          selected={selected}
          onSelectRestaurant={onSelectRestaurant}
          flyTo={flyTo}
          activeChannel={activeChannel}
        />
      </Map>
      {onMyLocation && (
        <button
          onClick={onMyLocation}
          aria-label="내 위치로 이동"
          // #278 — 44×44px 터치 영역 확보 (이전 36px)
          className="absolute top-2 right-2 w-11 h-11 bg-surface rounded-lg shadow-md flex items-center justify-center text-gray-600 dark:text-gray-300 hover:text-brand-500 dark:hover:text-brand-400 transition-colors z-10 touch-manipulation"
          title="내 위치"
        >
          <Icon name="my_location" size={22} />
        </button>
      )}
      {channelNames.length > 0 && (
        <div
          role="region"
          aria-label="채널 범례"
          className="absolute bottom-2 left-2 bg-surface/90 backdrop-blur-sm rounded-lg shadow px-2.5 py-1.5 flex flex-wrap gap-x-3 gap-y-1 text-[11px] z-10"
        >
          {channelNames.map((ch) => (
            <div key={ch} className="flex items-center gap-1">
              <span
                aria-hidden="true"
                className="inline-block w-2.5 h-2.5 rounded-full border"
                style={{ backgroundColor: channelColors[ch].border, borderColor: channelColors[ch].border }}
              />
              <span className="text-gray-700 dark:text-gray-300">{ch}</span>
            </div>
          ))}
        </div>
      )}
    </APIProvider>
  );
}
