"use client";

import { useEffect } from "react";
import { useTheme } from "next-themes";
import {
  AdvancedMarker,
  APILoadingStatus,
  APIProvider,
  ColorScheme,
  Map as GoogleMap,
  useApiLoadingStatus,
  useMap,
} from "@vis.gl/react-google-maps";
import { MapPin } from "lucide-react";
import { Button } from "@/components/ui/button";
import type { LocationDirectoryRecord } from "./api-contract";
import type { GoogleMapConfig } from "./location-map-model";

type MappedLocation = LocationDirectoryRecord & {
  latitude: number;
  longitude: number;
};

function MapCamera({
  points,
  selectedId,
}: {
  points: readonly MappedLocation[];
  selectedId: string;
}) {
  const map = useMap();

  useEffect(() => {
    if (!map || !points.length) return;
    const selected = points.find((point) => point.id === selectedId);
    if (selected) {
      map.panTo({ lat: selected.latitude, lng: selected.longitude });
      map.setZoom(15);
      return;
    }

    const bounds = points.reduce(
      (current, point) => ({
        north: Math.max(current.north, point.latitude),
        south: Math.min(current.south, point.latitude),
        east: Math.max(current.east, point.longitude),
        west: Math.min(current.west, point.longitude),
      }),
      {
        north: points[0].latitude,
        south: points[0].latitude,
        east: points[0].longitude,
        west: points[0].longitude,
      },
    );
    const samePoint = points.every(
      (point) =>
        point.latitude === points[0].latitude &&
        point.longitude === points[0].longitude,
    );
    if (samePoint) {
      map.setCenter({ lat: points[0].latitude, lng: points[0].longitude });
      map.setZoom(15);
    } else {
      map.fitBounds(bounds, 48);
    }
  }, [map, points, selectedId]);

  return null;
}

function MapLoadingStatus({ onUseOfflineMap }: { onUseOfflineMap: () => void }) {
  const status = useApiLoadingStatus();
  if (status === APILoadingStatus.LOADED) return null;
  const failed =
    status === APILoadingStatus.FAILED ||
    status === APILoadingStatus.AUTH_FAILURE;

  return (
    <div className="absolute inset-0 z-10 flex flex-col items-center justify-center gap-3 bg-card/95 p-6 text-center">
      <p role={failed ? "alert" : "status"} className={failed ? "text-destructive" : "text-muted-foreground"}>
        {failed
          ? "Google Maps could not load. Check the map configuration or use the offline map."
          : "Loading Google Maps…"}
      </p>
      {failed && (
        <Button type="button" variant="outline" size="sm" onClick={onUseOfflineMap}>
          Show offline map
        </Button>
      )}
    </div>
  );
}

export function GoogleLocationCanvas({
  points,
  selectedId,
  config,
  onSelect,
  onUseOfflineMap,
}: {
  points: readonly MappedLocation[];
  selectedId: string;
  config: GoogleMapConfig;
  onSelect: (id: string) => void;
  onUseOfflineMap: () => void;
}) {
  const { resolvedTheme } = useTheme();
  const markerGroups = new Map<string, MappedLocation[]>();
  for (const point of points) {
    const key = point.latitude.toFixed(6) + ":" + point.longitude.toFixed(6);
    markerGroups.set(key, [...(markerGroups.get(key) ?? []), point]);
  }
  const center = points.length
    ? { lat: points[0].latitude, lng: points[0].longitude }
    : { lat: -6.2, lng: 106.8167 };

  return (
    <APIProvider
      apiKey={config.apiKey}
      region="ID"
      language="en"
      solutionChannel=""
    >
      <div className="relative size-full overflow-hidden bg-muted">
        <GoogleMap
          mapId={config.mapId}
          defaultCenter={center}
          defaultZoom={14}
          colorScheme={resolvedTheme === "dark" ? ColorScheme.DARK : ColorScheme.LIGHT}
          gestureHandling="cooperative"
          mapTypeControl={false}
          streetViewControl={false}
          fullscreenControl={false}
          style={{ width: "100%", height: "100%" }}
        >
          <MapCamera points={points} selectedId={selectedId} />
          {[...markerGroups.entries()].map(([key, group]) => (
            <AdvancedMarker
              key={key}
              position={{ lat: group[0].latitude, lng: group[0].longitude }}
              title={group.map((point) => point.name).join(", ")}
              onClick={() => onSelect(group[0].id)}
            >
              <div className="flex size-10 items-center justify-center rounded-full border-2 border-background bg-primary text-primary-foreground shadow-lg">
                {group.length > 1 ? (
                  <span className="font-semibold">{group.length}</span>
                ) : (
                  <MapPin aria-hidden="true" className="size-5" />
                )}
              </div>
            </AdvancedMarker>
          ))}
        </GoogleMap>
        <MapLoadingStatus onUseOfflineMap={onUseOfflineMap} />
      </div>
    </APIProvider>
  );
}
