<template>
  <div class="map-preview">
    <div ref="mapContainer" class="map-container"></div>
    <div v-if="loading" class="map-loading">
      <div class="spinner"></div>
      <span>Loading map...</span>
    </div>
  </div>
</template>

<script>
import { ref, watch, onMounted, onBeforeUnmount, nextTick } from "vue";
import maplibregl from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";

export default {
  props: {
    center: {
      type: Object,
      required: true
    },
    zoom: {
      type: Number,
      required: true
    },
    markers: {
      type: Array,
      default: () => []
    },
    selectedMarkerId: {
      type: String,
      default: null
    }
  },

  setup(props, { emit }) {
    // State
    const mapContainer = ref(null);
    const map = ref(null);
    const loading = ref(true);
    const markerElements = ref(new Map());
    const isDragging = ref(false);

    // Lifecycle
    onMounted(async () => {
      await nextTick();
      initMap();
    });

    onBeforeUnmount(() => {
      if (map.value) {
        map.value.remove();
        map.value = null;
      }
      markerElements.value.clear();
    });

    // Watchers - only for updates FROM parent, not TO parent
    watch(() => props.center, (newCenter) => {
      if (map.value && map.value.loaded() && !isDragging.value) {
        const currentCenter = map.value.getCenter();
        // Only update if significantly different to avoid render loops
        if (Math.abs(currentCenter.lat - newCenter.lat) > 0.00001 ||
            Math.abs(currentCenter.lng - newCenter.lon) > 0.00001) {
          map.value.setCenter([newCenter.lon, newCenter.lat]);
        }
      }
    }, { deep: true });

    watch(() => props.zoom, (newZoom) => {
      if (map.value && map.value.loaded()) {
        const currentZoom = map.value.getZoom();
        // Only update if significantly different
        if (Math.abs(currentZoom - newZoom) > 0.01) {
          map.value.setZoom(newZoom);
        }
      }
    });

    watch(() => props.markers, () => {
      updateMarkers();
    }, { deep: true });

    watch(() => props.selectedMarkerId, (newId) => {
      updateMarkerSelection(newId);
    });

    // Methods
    function initMap() {
      if (!mapContainer.value) {
        console.error("Map container not found");
        return;
      }

      loading.value = true;

      try {
        map.value = new maplibregl.Map({
          container: mapContainer.value,
          style: {
            version: 8,
            sources: {
              osm: {
                type: "raster",
                tiles: [
                  "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
                  "https://b.tile.openstreetmap.org/{z}/{x}/{y}.png",
                  "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png"
                ],
                tileSize: 256,
                attribution:
                  '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
              }
            },
            layers: [
              {
                id: "osm",
                type: "raster",
                source: "osm",
                minzoom: 0,
                maxzoom: 19
              }
            ]
          },
          center: [props.center.lon, props.center.lat],
          zoom: props.zoom
        });

        map.value.on("load", () => {
          loading.value = false;
          updateMarkers();
        });

        // Handle map clicks to add markers
        map.value.on("click", (e) => {
          // Check if click was on a marker element
          const target = e.originalEvent.target;
          const isMarkerClick = target.closest('.custom-marker');

          if (!isMarkerClick) {
            const clickPos = {
              lat: e.lngLat.lat,
              lng: e.lngLat.lng
            };
            emit("map-click", clickPos);
          }
        });
      } catch (error) {
        console.error("Error initializing map:", error);
        loading.value = false;
      }
    }

    function updateMarkers() {
      if (!map.value || !map.value.loaded()) {
        return;
      }

      // Remove existing markers
      markerElements.value.forEach(({ marker }) => {
        if (marker) {
          marker.remove();
        }
      });
      markerElements.value.clear();

      // Add markers
      if (props.markers && Array.isArray(props.markers)) {
        props.markers.forEach((markerData, index) => {
          addMarkerToMap(markerData, index);
        });
      }
    }

    function addMarkerToMap(markerData, index) {
      if (!map.value || !markerData || !markerData.position) {
        return;
      }

      // Create marker element (outer wrapper for MapLibre positioning)
      const el = document.createElement("div");
      el.className = "custom-marker";

      // Create inner wrapper for visual transforms (isolates from MapLibre transforms)
      const inner = document.createElement("div");
      inner.className = "marker-inner";
      if (props.selectedMarkerId === markerData.id) {
        inner.classList.add("selected");
      }

      // Add marker number
      const numberEl = document.createElement("div");
      numberEl.className = "marker-number";
      numberEl.textContent = index + 1;
      inner.appendChild(numberEl);
      el.appendChild(inner);

      try {
        const coords = [markerData.position.lon, markerData.position.lat];

        // Create MapLibre marker
        // Anchor at bottom-center (where the pin tip is)
        const marker = new maplibregl.Marker({
          element: el,
          draggable: true,
          anchor: 'bottom'
        })
          .setLngLat(coords)
          .addTo(map.value);

        // Handle marker drag
        marker.on("dragstart", () => {
          isDragging.value = true;
        });

        marker.on("dragend", () => {
          const lngLat = marker.getLngLat();
          emit("marker-moved", {
            markerId: markerData.id,
            position: {
              lat: lngLat.lat,
              lng: lngLat.lng
            }
          });
          setTimeout(() => {
            isDragging.value = false;
          }, 100);
        });

        // Handle marker click
        el.addEventListener("click", (e) => {
          e.stopPropagation();
          emit("marker-click", markerData.id);
        });

        // Handle marker double-click
        el.addEventListener("dblclick", (e) => {
          e.stopPropagation();
          emit("marker-dblclick", markerData.id);
        });

        // Store marker reference
        markerElements.value.set(markerData.id, {
          marker,
          element: el
        });
      } catch (error) {
        console.error("Error adding marker to map:", error);
      }
    }

    function updateMarkerSelection(selectedId) {
      markerElements.value.forEach(({ element }, markerId) => {
        if (element) {
          const inner = element.querySelector('.marker-inner');
          if (inner) {
            if (markerId === selectedId) {
              inner.classList.add("selected");
            } else {
              inner.classList.remove("selected");
            }
          }
        }
      });
    }

    function getCurrentCenter() {
      if (map.value && map.value.loaded()) {
        const center = map.value.getCenter();
        return {
          lat: center.lat,
          lon: center.lng
        };
      }
      return {
        lat: props.center.lat,
        lon: props.center.lon
      };
    }

    function centerOnPosition(lat, lon) {
      if (map.value && map.value.loaded()) {
        map.value.flyTo({
          center: [lon, lat],
          zoom: map.value.getZoom(),
          duration: 1000
        });
      }
    }

    return {
      mapContainer,
      loading,
      getCurrentCenter,
      centerOnPosition
    };
  }
};
</script>

<style>
.map-preview {
  position: relative;
  width: 100%;
  height: 100%;
}

.map-container {
  width: 100%;
  height: 100%;
}

.map-loading {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  background: rgba(255, 255, 255, 0.9);
  z-index: 1000;
}

.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #3498db;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

/* Custom marker outer wrapper - NO transforms here, MapLibre handles positioning */
.custom-marker {
  /* MapLibre will position this element via transform: translate3d() */
  cursor: grab;
}

.custom-marker:active {
  cursor: grabbing;
}

/* Inner wrapper for visual styling - transforms are isolated here */
.marker-inner {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.marker-inner::before {
  content: "";
  position: absolute;
  width: 40px;
  height: 40px;
  background: #e74c3c;
  border: 3px solid white;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  transition: all 0.2s;
}

.marker-inner:hover::before {
  background: #c0392b;
  transform: rotate(-45deg) scale(1.1);
}

.marker-inner.selected::before {
  background: #3498db;
  border-color: #2980b9;
  box-shadow: 0 4px 12px rgba(52, 152, 219, 0.6);
}

.marker-number {
  position: relative;
  z-index: 1;
  color: white;
  font-weight: 700;
  font-size: 14px;
  line-height: 1;
  /* transform removed - was causing positioning issues */
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  pointer-events: none;
}

/* MapLibre controls styling */
.maplibregl-ctrl-group {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.maplibregl-ctrl-group button {
  width: 30px;
  height: 30px;
}

.maplibregl-ctrl-attrib {
  font-size: 11px;
  background: rgba(255, 255, 255, 0.8);
}

.maplibregl-canvas-container {
  cursor: crosshair;
}

.maplibregl-canvas-container.maplibregl-interactive {
  cursor: crosshair;
}
</style>
