<script lang="ts" setup>
import { Map } from "@/components/ui/map";
import {
  Preview,
  SectionTitle,
  SectionContent,
  InstallPackage,
  PreviewCode,
} from "@/components/docs";
const markersData = {
  type: "FeatureCollection" as const,
  features: [
    {
      type: "Feature" as const,
      properties: { name: "Cafe Berlin", type: "cafe" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.388, 52.517],
      },
    },
    {
      type: "Feature" as const,
      properties: { name: "Restaurant Alex", type: "restaurant" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.39, 52.518],
      },
    },
    {
      type: "Feature" as const,
      properties: { name: "Coffee House", type: "cafe" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.385, 52.515],
      },
    },
    {
      type: "Feature" as const,
      properties: { name: "Pizza Place", type: "restaurant" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.392, 52.519],
      },
    },
    {
      type: "Feature" as const,
      properties: { name: "Burger Joint", type: "restaurant" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.387, 52.516],
      },
    },
    {
      type: "Feature" as const,
      properties: { name: "Starbucks", type: "cafe" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.391, 52.52],
      },
    },
    {
      type: "Feature" as const,
      properties: { name: "Sushi Bar", type: "restaurant" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.395, 52.522],
      },
    },
    {
      type: "Feature" as const,
      properties: { name: "Bakery", type: "cafe" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.383, 52.514],
      },
    },
    {
      type: "Feature" as const,
      properties: { name: "Italian Restaurant", type: "restaurant" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.398, 52.525],
      },
    },
    {
      type: "Feature" as const,
      properties: { name: "Tea House", type: "cafe" },
      geometry: {
        type: "Point" as const,
        coordinates: [13.38, 52.512],
      },
    },
  ],
};
</script>

<template>
  <div id="preview" class="-mt-20">
    <Preview>
      <template #preview>
        <Map class="w-full h-96" :center="[13.388, 52.517]" :zoom="9.5" :markers="markersData" />
      </template>
      <template #code>
        <PreviewCode>
          {{ `
          <Map class="w-full h-96" :center="[13.388, 52.517]" :zoom="9.5" :markers="markersData" />
          ` }}
        </PreviewCode>
      </template>
    </Preview>
  </div>
  <div id="installation">
    <SectionTitle>Installation</SectionTitle>
    <SectionContent>Install the following dependencies:</SectionContent>
    <InstallPackage>add maplibre-gl</InstallPackage>
    <SectionContent>
      Copy and paste the following code into your project.
    </SectionContent>
    <PreviewCode title="components/ui/map/Map.vue">
      {{`
      <${""}script setup lang="ts">
import "maplibre-gl/dist/maplibre-gl.css";
import maplibregl, { type MapOptions } from "maplibre-gl";
import { ref, onMounted } from "vue";
import { Button } from "@/components/ui/button";
import { Plus, Minus, MapPin, Compass, Expand, X } from "@lucide/vue";
import type { FeatureCollection, Point } from "geojson";
import { cn } from "@mykopkb/core/utils/cn";
import { map } from "@mykopkb/core/styles/map.styles";

const mapRef = ref();
const mapInstance = ref<maplibregl.Map>();
const isFullscreen = ref(false);

const {
  class: className,
  markers,
  ...props
} = defineProps<
  Partial<MapOptions> & {
    class?: string;
    markers?: FeatureCollection<Point>;
  }
>();

onMounted(() => {
  mapInstance.value = new maplibregl.Map({
    ...Object.fromEntries(Object.entries(props).filter(([_, value]) => value)),
    style: "https://tiles.openfreemap.org/styles/positron",
    container: mapRef.value,
  });

  markers &&
    mapInstance.value.on("load", () => {
      // Add source with clustering
      mapInstance.value!.addSource("markers", {
        type: "geojson",
        data: markers,
        cluster: true,
        clusterMaxZoom: 14, // Max zoom for clustering
        clusterRadius: 50, // Cluster radius in pixels
      });

      // Layer for clusters (circles)
      mapInstance.value!.addLayer({
        id: "clusters",
        type: "circle",
        source: "markers",
        filter: ["has", "point_count"],
        paint: {
          "circle-color": [
            "step",
            ["get", "point_count"],
            "#cccccc", // Color for < 5 points
            5,
            "#cccccc", // Color for 5-10 points
            10,
            "#cccccc", // Color for > 10 points
          ],
          "circle-radius": [
            "step",
            ["get", "point_count"],
            20, // Radius for < 5 points
            5,
            30, // Radius for 5-10 points
            10,
            40, // Radius for > 10 points
          ],
        },
      });

      // Layer for cluster count numbers
      mapInstance.value!.addLayer({
        id: "cluster-count",
        type: "symbol",
        source: "markers",
        filter: ["has", "point_count"],
        layout: {
          "text-field": "{point_count_abbreviated}",
          "text-font": ["Open Sans Bold"],
          "text-size": 12,
        },
      });

      // Layer for individual points (unclustered)
      mapInstance.value!.addLayer({
        id: "unclustered-point",
        type: "circle",
        source: "markers",
        filter: ["!", ["has", "point_count"]],
        paint: {
          "circle-color": "#333333",
          "circle-radius": 8,
          "circle-stroke-width": 2,
          "circle-stroke-color": "#ffffff",
        },
      });

      // Click on cluster to zoom in
      mapInstance.value!.on("click", "clusters", async (e) => {
        const features = mapInstance.value!.queryRenderedFeatures(e.point, {
          layers: ["clusters"],
        });

        const clusterId = features[0]?.properties.cluster_id;
        const source = mapInstance.value!.getSource(
          "markers"
        ) as maplibregl.GeoJSONSource;

        try {
          const zoom = await source.getClusterExpansionZoom(clusterId);

          mapInstance.value!.easeTo({
            center: (features[0]?.geometry as any).coordinates,
            zoom: zoom,
          });
        } catch (err) {
          console.error("Error getting cluster expansion zoom:", err);
        }
      });

      // Click on individual point to show popup
      mapInstance.value!.on("click", "unclustered-point", (e) => {
        const coordinates = (
          e.features![0]?.geometry as any
        ).coordinates.slice();
        const { name, type } = (e.features![0]?.properties || {}) as any;

        new maplibregl.Popup()
          .setLngLat(coordinates)
          .setHTML(\`<h3>\${name}</h3><p>\${type}</p>\`)
          .addTo(mapInstance.value!);
      });

      // Change cursor on hover cluster/point
      mapInstance.value!.on("mouseenter", "clusters", () => {
        mapInstance.value!.getCanvas().style.cursor = "pointer";
      });
      mapInstance.value!.on("mouseleave", "clusters", () => {
        mapInstance.value!.getCanvas().style.cursor = "";
      });
      mapInstance.value!.on("mouseenter", "unclustered-point", () => {
        mapInstance.value!.getCanvas().style.cursor = "pointer";
      });
      mapInstance.value!.on("mouseleave", "unclustered-point", () => {
        mapInstance.value!.getCanvas().style.cursor = "";
      });
    });
});

const zoomIn = () => {
  mapInstance.value?.zoomIn();
};

const zoomOut = () => {
  mapInstance.value?.zoomOut();
};

const resetNorth = () => {
  mapInstance.value?.easeTo({ bearing: 0, pitch: 0 });
};

const locateMe = () => {
  if (!navigator.geolocation) {
    alert("Geolocation is not supported by your browser");
    return;
  }

  navigator.geolocation.getCurrentPosition(
    (position) => {
      const { longitude, latitude } = position.coords;
      mapInstance.value?.flyTo({
        center: [longitude, latitude],
        zoom: 14,
      });

      new maplibregl.Marker({ color: "var(--color-foreground)" })
        .setLngLat([longitude, latitude])
        .addTo(mapInstance.value!);
    },
    (error) => {
      alert("Failed to get location: " + error.message);
    }
  );
};

const toggleFullscreen = () => {
  if (!mapRef.value) return;

  if (!isFullscreen.value) {
    if (mapRef.value.requestFullscreen) {
      mapRef.value.requestFullscreen();
    }
  } else {
    if (document.exitFullscreen) {
      document.exitFullscreen();
    }
  }
  isFullscreen.value = !isFullscreen.value;
};
</${""}script>

      <template>
        <div data-scope="map" data-part="root" ref="mapRef" :class="cn(map, className)">
          <div data-scope="map" data-part="controls">
            <Button data-scope="map" data-part="zoom-in" @click="zoomIn" variant="ghost" size="sm">
              <Plus />
            </Button>
            <Button data-scope="map" data-part="zoom-out" @click="zoomOut" variant="ghost" size="sm">
              <Minus />
            </Button>
            <Button data-scope="map" data-part="reset-north" @click="resetNorth" variant="ghost" size="sm">
              <Compass />
            </Button>
            <Button data-scope="map" data-part="locate" @click="locateMe" variant="ghost" size="sm">
              <MapPin />
            </Button>
            <Button data-scope="map" data-part="toggle-fullscreen" @click="toggleFullscreen" variant="ghost" size="sm">
              <Expand v-if="!isFullscreen" />
              <X v-else />
            </Button>
          </div>
        </div>
      </template>
      ` }}
    </PreviewCode>
    <PreviewCode title="components/ui/map/index.ts">
      {{ `
      export { default as Map } from "./Map.vue";
      ` }}
    </PreviewCode>
    <SectionContent>
      Update the import paths to match your project setup.
    </SectionContent>
  </div>
  <div id="usage">
    <SectionTitle>Usage</SectionTitle>
    <PreviewCode>
      {{ `
      import { Map } from "@/components/ui/map";
      ` }}
    </PreviewCode>
    <PreviewCode>
      {{ `
      <Map class="w-full h-96" :center="[13.388, 52.517]" :zoom="9.5" :markers="markersData" />
      ` }}
    </PreviewCode>
  </div>
</template>
