<script setup lang="ts">
import { onMounted, ref, watch, nextTick, onUnmounted, shallowRef, markRaw } from "vue";
import { useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { useRouteStore } from "@/stores/route";
import { useMapStore } from "@/stores/map";
import { useCouponStore } from "@/stores/coupon";
import { useAuthStore } from "@/stores/auth";
import { useGoogleMaps } from "@/composables/useGoogleMaps";
import { analyticsService } from "@/services/analyticsService";
import { getImageUrl } from "@/utils/imageUrl";

import { useDirectionsRoute } from "@/composables/useDirectionsRoute";
import { useParadaCercana } from "@/composables/useParadaCercana";
import { useETA } from "@/composables/useETA";
import { useFlujoPrincipal } from "@/composables/useFlujoPrincipal";
import { useMapState } from "@/composables/useMapState";

// Optimized Components (Extracted)
import SearchOverlay from "@/components/map/SearchOverlay.vue";
import PromoCarousel from "@/components/map/PromoCarousel.vue";
import ArrivalBanner from "@/components/map/ArrivalBanner.vue";

import ETACard from "@/components/map/ETACard.vue";
import type { BusStop } from '@/types'

const router = useRouter();
const { t } = useI18n();

const routeStore = useRouteStore();
const mapStore = useMapStore();
const couponStore = useCouponStore();
const authStore = useAuthStore();

const { map, isLoaded, error: mapsError, initMap, addHtmlMarker, setCenter, setZoom, addMarker, addCleanMarker } = useGoogleMaps();
const { estasCargando: estasCargandoRuta, errorRuta } = useDirectionsRoute();
const { encontrarParadaCercana, paradaCercana, distanciaMetros, duracionCaminata, limpiarCaminata } = useParadaCercana();
const { calcularETA, busesActivos, cargando: etaCargando } = useETA();

const { procesarSeleccionDeRuta, cargando: flujoCargando } = useFlujoPrincipal();
const { limpiarMapa: limpiarTodoCentralizado } = useMapState();

const showETACard = ref(false);
const routePhase = ref<'idle' | 'eta' | 'navigating'>('idle');

// PERFORMANCE FIX: Use shallowRef for heavy object arrays and Map objects
const promoMarkers = shallowRef<any[]>([]);
const userMarker = shallowRef<any>(null);
const isUpdatingMarkers = ref(false);
// Cancellation token: increment to invalidate any in-flight marker draw
const markerGenerationId = ref(0);
// Object-based cancel token passed into procesarSeleccionDeRuta so it can abort from within
let currentCancelToken: { cancelled: boolean } = { cancelled: false };
const unitMarkers = shallowRef<Map<string, any>>(new Map());
const unitFetchInterval = ref<any>(null);
const userCoords = ref<{ lat: number; lng: number } | null>(null);
const showUberSearch = ref(false);
const showPromos = ref(false);
const isBannerClosing = ref(false);
const showPromoModal = ref(false);
const selectedPromo = ref<any>(null);
const currentCarouselIndex = ref(0);
const carouselTimer = ref<any>(null);
const isMapMoved = ref(false);

// Search optimization: Simple debounce implementation
// REQUISITO TÉCNICO: Implementar geolocalización automática al iniciar sesión.
function calculateDistance(point1: { lat: number; lng: number }, point2: { lat: number; lng: number }) {
  const R = 6371; // Radio de la Tierra en km
  const dLat = (point2.lat - point1.lat) * Math.PI / 180;
  const dLng = (point2.lng - point1.lng) * Math.PI / 180;
  const a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(point1.lat * Math.PI / 180) * Math.cos(point2.lat * Math.PI / 180) *
    Math.sin(dLng/2) * Math.sin(dLng/2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  return R * c;
}

function updateIsMapMoved() {
  if (!map.value || !userCoords.value) return;
  const center = map.value.getCenter();
  if (!center) return;
  
  const dist = calculateDistance(
    { lat: center.lat(), lng: center.lng() },
    userCoords.value
  );
  
  // Si se movió más de 0.1 km (100 metros), mostrar botón
  isMapMoved.value = dist > 0.1;
}

function openUberSearch() {
  showPromos.value = false;
  showUberSearch.value = true;
}

function closeUberSearch() {
  showUberSearch.value = false;
}

async function animateAndReload() {
  isBannerClosing.value = true;

  // 🔥 CANCELACIÓN TOTAL: invalidar la operación en vuelo desde adentro Y desde afuera
  markerGenerationId.value++;
  currentCancelToken.cancelled = true;    // aborta procesarSeleccionDeRuta desde adentro
  currentCancelToken = { cancelled: false }; // prepara un token limpio para la próxima operación
  isUpdatingMarkers.value = false;         // liberar el lock

  routeStore.setWasSelectedFromMap(false);

  // Limpiar mapa INMEDIATAMENTE - dos capas de limpieza
  clearMapMarkers();           // limpia markers[] y globalOverlays
  limpiarTodoCentralizado();   // limpia polylines[], infoWindows[], circles[]
  limpiarCaminata();

  routeStore.clearSelection();
  router.replace({ query: {} });

  showETACard.value = false;
  routePhase.value = 'idle';

  // Segunda pasada tras el tick: por si algún await en vuelo terminó justo antes
  await nextTick();
  clearMapMarkers();
  limpiarTodoCentralizado();

  if (map.value) {
    setCenter(mapStore.center.lat, mapStore.center.lng);
    setZoom(mapStore.zoom);
  } else {
    await initializeMap();
  }

  setTimeout(() => {
    isBannerClosing.value = false;
  }, 500);
}

function handlePromoClick(promo: any) {
  selectedPromo.value = promo;
  showPromoModal.value = true;
}

function closePromoModal() {
  showPromoModal.value = false;
  selectedPromo.value = null;
}

async function fetchData(isBackground = false) {
  // Estas son actualizaciones asíncronas no urgentes para render principal
  Promise.all([
    routeStore.loadRoutes(undefined, false, isBackground),
    couponStore.loadCoupons({ active_only: true }, isBackground)
  ]);
  
  // Update super-urgente, dibuja los buses actuales en el mapa al instante
  updateActiveUnits();
}

async function handleRefocus() {
  // Refrescar datos en fondo de manera silenciosa (isBackground = true)
  fetchData(true);

  await nextTick();

  if (map.value) {
    // El mapa sigue vivo — solo redimensionar y actualizar
    try {
      google.maps.event.trigger(map.value, 'resize');
    } catch (_) { /* ignorar si google no disponible */ }
    updateActiveUnits();
  } else {
    // El mapa fue destruido por el browser al suspender la pestaña — reinicializar
    console.log('SIB | Mapa perdido tras refocus, reinicializando...');
    if (isLoaded.value) {
      await initializeMap();
    } else {
      const unwatch = watch(isLoaded, async (loaded) => {
        if (loaded) { await initializeMap(); unwatch(); }
      });
    }
  }
}

// Map initialization & Lifecycle
onMounted(async () => {
  analyticsService.logEvent({ event_name: 'screen_view', properties: { screen_name: 'Map' } })
  window.addEventListener('app-refocus', handleRefocus);

  await fetchData();

  const queryRouteId = router.currentRoute.value.query.routeId as string;
  if (queryRouteId && queryRouteId !== routeStore.selectedRouteId) {
    const foundRoute = routeStore.allRoutes.find(r => r.id === queryRouteId);
    if (foundRoute) {
      await routeStore.selectRoute(foundRoute.id, foundRoute.name);
    }
  }

  if (isLoaded.value) {
    await initializeMap();
  } else {
    const unwatch = watch(isLoaded, async (loaded) => {
      if (loaded) {
        await initializeMap();
        unwatch();
      }
    });
  }

  unitFetchInterval.value = setInterval(updateActiveUnits, 15000);
  startCarousel();

  document.addEventListener('visibilitychange', handleVisibilityChange);
});

onUnmounted(() => {
  if (unitFetchInterval.value) clearInterval(unitFetchInterval.value);
  if (carouselTimer.value) clearInterval(carouselTimer.value);
  document.removeEventListener('visibilitychange', handleVisibilityChange);
  window.removeEventListener('app-refocus', handleRefocus);
});

function handleVisibilityChange() {
  if (document.visibilityState === 'visible' && map.value) {
    try {
      google.maps.event.trigger(map.value, 'resize');
    } catch (_) { /* ignorar */ }
    updateActiveUnits();
  }
}

async function initializeMap() {
  await nextTick();
  
  initMap("map", mapStore.center, mapStore.zoom);
  
  if (map.value) {
    // PERFORMANCE: Use passive listeners for native events if added (Google Maps doesn't expose this directly easily)
    map.value.addListener('click', () => {
      if (showETACard.value) handleETACardDismiss();
    });

    // Detect user interaction with the map to show/hide location button
    map.value.addListener('center_changed', updateIsMapMoved);
    map.value.addListener('dragstart', () => {
      // Forzar visibilidad inmediata en drag si se desea un feedback instantáneo,
      // pero el watcher de distancia es el que manda finalmente.
      isMapMoved.value = true;
    });
  }
  
  updatePromoMarkers();
  
  if (authStore.userProfile?.auto_location) {
    locateUser();
  }

  if (routeStore.selectedRouteId && routeStore.wasSelectedFromMap) {
    if (routeStore.selectedRouteStops.length === 0) {
      await routeStore.loadRouteStops(routeStore.selectedRouteId);
    }
    updateMapMarkers();
    routePhase.value = 'navigating'; // Restaurar en modo navegación al volver
  } else {
    clearMapMarkers();
  }
}

// MARKER RECYCLING & REACTIVITY OPTIMIZATION
function clearMapMarkers() {
  // Cancelar cualquier operación async en vuelo ANTES de limpiar el mapa.
  // Sin esto, una llamada a encontrarParadaCercana que termine después del cleanup
  // dibuja una polilínea huérfana que nunca se limpia.
  currentCancelToken.cancelled = true;
  currentCancelToken = { cancelled: false }; // token limpio para la próxima operación
  isUpdatingMarkers.value = false;           // liberar lock

  limpiarTodoCentralizado();
  limpiarCaminata(); // garantizar que el ref de la polyline de caminata quede limpio
  
  // Limpiar también los marcadores de las unidades (buses)
  if (unitMarkers.value.size > 0) {
    unitMarkers.value.forEach(m => m.setMap(null));
    unitMarkers.value.clear();
  }

  if (userCoords.value) {
     reDrawUserMarker();
  }
}

function reDrawUserMarker() {
    if (!userCoords.value || !map.value) return;
    if (userMarker.value && typeof userMarker.value.setMap === 'function') {
        userMarker.value.setMap(null);
    }
    
    userMarker.value = markRaw(addHtmlMarker(
        { lat: userCoords.value.lat, lng: userCoords.value.lng },
        sonarHtml,
        { x: -30, y: -30 }
    )!);
}

async function updateMapMarkers(skipZoom = false) {
  if (!isLoaded.value || !map.value) return;

  const currentRequestRouteId = routeStore.selectedRouteId;
  if (!currentRequestRouteId) {
    clearMapMarkers();
    return;
  }

  // ── CANCELACIÓN EXPLÍCITA: invalidar la operación anterior en vuelo.
  // Si NO se hace esto, el token viejo queda en cancelled=false y la
  // encontrarParadaCercana anterior dibuja una polilínea huérfana al completarse.
  currentCancelToken.cancelled = true;
  isUpdatingMarkers.value = false; // liberar lock antes de crear el nuevo

  // Capturar el token de generación ANTES de cualquier await
  markerGenerationId.value++;
  const myGeneration = markerGenerationId.value;
  // Crear un token de cancelación para esta operación específica
  const myToken = { cancelled: false };
  currentCancelToken = myToken;

  isUpdatingMarkers.value = true;
  
  try {
    const selectedRouteObj = routeStore.allRoutes.find(r => r.id === currentRequestRouteId) || { id: currentRequestRouteId, short_name: currentRequestRouteId };
    
    // Guard de generación: si se canceló mientras esperabamos, abortar
    if (myToken.cancelled || markerGenerationId.value !== myGeneration) {
      limpiarTodoCentralizado();
      return;
    }

    await procesarSeleccionDeRuta(
      selectedRouteObj, 
      routeStore.selectedRouteStops,
      map.value, 
      addCleanMarker, 
      skipZoom,
      (stop: BusStop) => {
        // Solo actualizar si aún somos la generación vigente
        if (!myToken.cancelled && markerGenerationId.value === myGeneration) {
          paradaCercana.value = stop;
          showETACard.value = true;
        }
      },
      myToken  // <-- pasar el cancel token al composable
    );

    // Guard final: verificar que no se canceló durante el await largo
    if (myToken.cancelled || markerGenerationId.value !== myGeneration || routeStore.selectedRouteId !== currentRequestRouteId) {
      clearMapMarkers();
      limpiarTodoCentralizado();
      return;
    }

    reDrawUserMarker();
    
    if (routeStore.wasSelectedFromMap && !skipZoom) {
        await highlightOptimalStopForRoute();
    }
  } finally {
    // Solo liberar el lock si somos la generación actual
    if (markerGenerationId.value === myGeneration) {
      isUpdatingMarkers.value = false;
    }
  }
}

async function updatePromoMarkers() {
  if (!isLoaded.value) return;

  promoMarkers.value.forEach(m => m.setMap(null));
  const newMarkers: any[] = [];

  const promosWithCoords = couponStore.coupons.filter(c => 
    c.is_active && c.business && c.business.latitude && c.business.longitude
  );

  promosWithCoords.forEach(promo => {
    const marker = addMarker(
      { lat: promo.business!.latitude!, lng: promo.business!.longitude! },
      {
        title: promo.title,
        icon: {
          path: "M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.65-.5-.65C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8.62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z",
          fillColor: '#FF4081',
          fillOpacity: 1,
          strokeColor: '#FFFFFF',
          strokeWeight: 2,
          anchor: new google.maps.Point(12, 12),
          scale: 2
        }
      }
    );
    if (marker) {
      const rawMarker = markRaw(marker);
      rawMarker.addListener('click', () => handlePromoClick(promo));
      newMarkers.push(rawMarker);
    }
  });
  promoMarkers.value = newMarkers;
}

// Carousel logic
function startCarousel() {
  if (carouselTimer.value) clearInterval(carouselTimer.value);
  carouselTimer.value = setInterval(() => {
    if (couponStore.coupons.length > 0) {
      currentCarouselIndex.value = (currentCarouselIndex.value + 1) % couponStore.coupons.length;
    }
  }, 5000);
}

function stopCarousel() {
  if (carouselTimer.value) clearInterval(carouselTimer.value);
}

function selectRouteAndClose(route: any) {
  if (routeStore.selectedRouteId === route.id) {
    showUberSearch.value = false;
    highlightOptimalStopForRoute();
    return;
  }
  
  showUberSearch.value = false;
  routeStore.setWasSelectedFromMap(true);
  routeStore.selectRoute(route.id, route.name);
}

async function updateActiveUnits() {
  if (!isLoaded.value || !routeStore.selectedRouteId) return;
  // Llamamos a calcularETA incluso si no hay paradaCercana aún para un chequeo rápido de disponibilidad
  await calcularETA(routeStore.selectedRouteId, (paradaCercana.value as BusStop) || null);
}

function locateUser(): Promise<void> {
  return new Promise((resolve) => {
    if (!navigator.geolocation) { 
      console.warn('Geolocation no soportado');
      return resolve(); 
    }
    
    navigator.geolocation.getCurrentPosition(
      (position) => {
        const { latitude, longitude } = position.coords;
        userCoords.value = { lat: latitude, lng: longitude };
        
        // Centrar y mostrar
        if (map.value) {
            setCenter(latitude, longitude);
            setZoom(16);
        }
        
        reDrawUserMarker();
        isMapMoved.value = false;
        resolve();
      },
      (error) => {
        console.error('SIB | Error obteniendo ubicación:', error);
        // Si falló por falta de permisos o error y el usuario tenía auto_location activo, 
        // lo desactivamos para no re-intentar infinitamente
        if (authStore.userProfile?.auto_location) {
           authStore.updateProfile({ auto_location: false });
        }
        resolve();
      },
      // maximumAge: 5 min — al volver del background, usa posición cacheada inmediatamente
      // en lugar de esperar que el GPS se reactive (evita timeout al desbloquear pantalla)
      { enableHighAccuracy: false, timeout: 6000, maximumAge: 300000 }
    );
  });
}

async function highlightOptimalStopForRoute() {
  if (!userCoords.value) { await locateUser(); }
  else { reDrawUserMarker(); }

  if (!userCoords.value || routeStore.selectedRouteStops.length === 0) return;
  
  try {
    await encontrarParadaCercana(userCoords.value, routeStore.selectedRouteStops as BusStop[], map.value || undefined, currentCancelToken);
  } catch (e) {
    console.error('Error calculating optimal stop:', e);
  }
}

const sonarHtml = `
  <div style="position: relative; width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;">
    <div style="position: absolute; width: 100%; height: 100%; border-radius: 50%; background-color: rgba(0, 212, 255, 0.5); animation: sonar-pulse 2.5s infinite ease-out;"></div>
    <div style="position: absolute; width: 100%; height: 100%; border-radius: 50%; background-color: rgba(0, 212, 255, 0.3); animation: sonar-pulse 2.5s infinite ease-out; animation-delay: 1.25s;"></div>
    <div style="width: 16px; height: 16px; background-color: #00d4ff; border-radius: 50%; box-shadow: 0 0 20px #00d4ff, 0 0 40px rgba(0, 212, 255, 0.6); border: 2px solid white; z-index: 2;"></div>
    <style> @keyframes sonar-pulse { 0% { transform: scale(0.1); opacity: 0.8; } 100% { transform: scale(4); opacity: 0; } } </style>
  </div>
`;

// Watch for route selection changes
// Watch for ETA loading to automatically show ETACard if no buses are available
// REVERTED: Stop automatic opening and clearing
/*
watch([etaCargando, () => busesActivos.value.length], ([loading, count]) => {
  if (!loading && count === 0 && routeStore.selectedRouteId && routeStore.wasSelectedFromMap) {
    showETACard.value = true;
    
    // PROBLEMA 2 & 3: Limpieza automática cuando no hay buses
    // Reseteamos el estado de la ruta en el store para que el buscador se limpie
    // y el mapa se limpie a través de los watchers existentes.
    
    // Pequeño delay para asegurar que ETACard capture los datos antes de limpiar el store
    setTimeout(() => {
        if (showETACard.value && busesActivos.value.length === 0 && routeStore.selectedRouteId) {
            routeStore.clearSelection();
            router.replace({ query: {} });
            console.log("SIB | Ruta autolimpiada por falta de buses");
        }
    }, 300);
  }
});
*/

// Cuando el usuario hace drag-down en el ETACard → pasar a fase 'navigating'
// Esto muestra el ArrivalBanner arriba y las paradas quedan en el mapa
function handleETACardDismiss() {
  showETACard.value = false;
  routePhase.value = 'navigating';
}

function handleBannerClick() {
  // Al tocar el banner superior, volver a mostrar el ETACard
  showETACard.value = true;
  routePhase.value = 'eta';
}

// Watch for route selection changes
watch(() => routeStore.selectedRouteId, (routeId) => {
  if (routeId) {
    if (routeStore.wasSelectedFromMap) {
      // Al seleccionar ruta: dibujar mapa + mostrar ETACard (fase 'eta')
      updateMapMarkers(false);
      updateActiveUnits();
      showETACard.value = true;
      routePhase.value = 'eta';
    } else {
      clearMapMarkers();
    }
  } else {
    clearMapMarkers();
    showETACard.value = false;
    routePhase.value = 'idle';
  }
});

// Watch for paradaCercana to recalculate ETA as soon as it's identified
// Y abrir el ETACard automáticamente cuando ya tenemos la parada
watch(paradaCercana, (newStop) => {
    if (newStop && routeStore.selectedRouteId) {
        updateActiveUnits();
    }
});

function handleImageError(event: Event) {
  (event.target as HTMLImageElement).src = getImageUrl(null, 'coupon');
}

// Watch for user profile to trigger location if preference is enabled OR on auth changes
// Nota: solo se activa si NO tenemos coordenadas aún Y el mapa está cargado.
// Se evita re-disparar por TOKEN_REFRESHED porque onAuthStateChange ya no recarga
// el perfil en ese evento, así que userProfile no cambia al despertar la pantalla.
watch([() => authStore.userProfile?.auto_location, isLoaded], ([canLocate, loaded], [prevCanLocate]) => {
  // Solo localizar si: el mapa cargó, auto_location está activo,
  // y NO tenemos coords aún (o el mapa se reinicializó sin coords)
  if (canLocate && loaded && !userCoords.value) {
    // Extra guard: no re-disparar si auto_location no cambió (solo isLoaded cambió)
    // Esto previene relocalización innecesaria al volver del background
    if (prevCanLocate !== undefined || !userCoords.value) {
      console.log('SIB | Iniciando geolocalización automática...');
      locateUser();
    }
  }
}, { immediate: true });
</script>

<template>
  <div class="split-view">
    <div class="map-side">
      <div class="map-view">
        <div v-if="flujoCargando || estasCargandoRuta || errorRuta" class="status-indicator">
          <div v-if="flujoCargando || estasCargandoRuta" class="loading-pill">{{ t('map.calculatingRoute') }}</div>
          <div v-if="errorRuta" class="error-pill">{{ errorRuta }}</div>
        </div>

        <div class="map-container">
          <div v-if="mapsError" class="error">
            <div class="error-content">
              <h3>⚠️ {{ t('map.mapLoadingError') }}</h3>
              <div class="error-detail">{{ mapsError }}</div>
            </div>
          </div>
          <div v-else-if="!isLoaded" class="loading">
            <p>{{ t('map.loadingMap') }}</p>
          </div>
          <div id="map" class="map" :style="{ display: isLoaded ? 'block' : 'none' }"></div>
          
          <div class="map-floating-controls">
            <button v-if="isLoaded && !showPromos && couponStore.coupons.length > 0" class="offers-fab pulse" @click="showPromos = true">
              <span class="material-icons">local_offer</span>
              <span v-if="couponStore.coupons.length > 0" class="offers-badge">{{ couponStore.coupons.length }}</span>
            </button>

            <!-- SMART LOCATION BUTTON: Hidden by default if auto-location is active, shows up with text when map moved -->
            <Transition name="fade-scale">
              <button 
                v-if="isLoaded && (!authStore.userProfile?.auto_location || isMapMoved)" 
                class="location-btn-smart" 
                :class="{ 'moved': isMapMoved }"
                @click="locateUser"
              >
                <div class="btn-content">
                  <span class="material-icons">my_location</span>
                  <span v-if="isMapMoved" class="btn-text">Volver a Mi Ubicación</span>
                </div>
              </button>
            </Transition>
          </div>
        </div>

        <!-- COMPONENTIZED SEARCH & BANNER -->
        <SearchOverlay 
          :show-panel="showUberSearch"
          :is-compact="!!(routeStore.selectedRouteId && routeStore.wasSelectedFromMap)"
          :is-route-active="!!routeStore.selectedRouteId"
          :all-routes="routeStore.allRoutes"
          :selected-route-id="routeStore.selectedRouteId"
          :was-selected-from-map="routeStore.wasSelectedFromMap"
          @open="openUberSearch"
          @close="closeUberSearch"
          @select-route="selectRouteAndClose"
        >
          <template #extra-triggers>
            <ArrivalBanner 
              :is-visible="(routePhase === 'navigating' || routePhase === 'eta') && !!(routeStore.selectedRouteId && !isBannerClosing)"
              :stop-name="paradaCercana?.name || routeStore.selectedRouteName || ''"
              :is-loading="etaCargando"
              :has-active-buses="busesActivos.length > 0"
              :eta-value="busesActivos[0]?.etaMinutos ?? 0"
              @close="animateAndReload"
              @click="handleBannerClick"
            />
          </template>
        </SearchOverlay>
      </div>
    </div>

    <!-- COMPONENTIZED PROMOS -->
    <PromoCarousel 
      :is-open="showPromos"
      :coupons="couponStore.coupons"
      :current-index="currentCarouselIndex"
      @update:index="currentCarouselIndex = $event"
      @close="showPromos = false"
      @prev="currentCarouselIndex = (currentCarouselIndex - 1 + couponStore.coupons.length) % couponStore.coupons.length"
      @next="currentCarouselIndex = (currentCarouselIndex + 1) % couponStore.coupons.length"
      @pause="stopCarousel"
      @resume="startCarousel"
      @promo-click="handlePromoClick"
    />

    <!-- MODALS & CARDS -->
    <Transition name="modal-fade">
      <div v-if="showPromoModal && selectedPromo" class="promo-modal-overlay" @click="closePromoModal">
        <div class="promo-modal-content" @click.stop>
          <div class="promo-header-modal">
            <img :src="getImageUrl(selectedPromo.image_url, 'coupon')" class="promo-img-modal" @error="handleImageError" />
            <div class="promo-badge-modal">{{ t('map.promo') }}</div>
          </div>
          <div class="promo-body-modal">
            <h2 class="promo-title-modal">{{ selectedPromo.title }}</h2>
            <div class="promo-biz">{{ selectedPromo.business?.name }}</div>
            <p>{{ selectedPromo.description }}</p>
          </div>
          <div class="promo-actions-modal">
            <button class="business-detail-btn-modal" @click="router.push('/business/' + selectedPromo.business_id)">
              {{ t('business.viewBusiness') }}
            </button>
          </div>
        </div>
      </div>
    </Transition>
    
    <ETACard
      :is-open="showETACard"
      :stop-name="paradaCercana?.name || ''"
      :walk-distance="distanciaMetros"
      :walk-duration="duracionCaminata"
      :buses="busesActivos"
      :is-loading="etaCargando || isUpdatingMarkers || flujoCargando"
      @close="handleETACardDismiss"
      @refresh="paradaCercana && routeStore.selectedRouteId ? calcularETA(routeStore.selectedRouteId, paradaCercana) : null"
    />
  </div>
</template>

<style scoped>
.split-view {
  display: flex;
  width: 100%;
  height: calc(100vh - 64px);
  overflow: hidden;
  position: relative;
}

.map-side, .map-view, .map-container, .map {
  width: 100%;
  height: 100%;
  position: relative;
}

.status-indicator {
  position: absolute;
  top: 1rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

.loading-pill {
  background: #1e40af;
  color: white;
  padding: 0.5rem 1rem;
  border-radius: 9999px;
  font-size: 0.875rem;
  animation: pulse 2s infinite;
}

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }

.error-content { text-align: center; padding: 20px; }
.error-detail { color: var(--text-primary); background: var(--bg-secondary); padding: 15px; border-radius: 8px; margin-top: 10px; }

.map-floating-controls {
  position: fixed;
  bottom: calc(95px + var(--safe-area-bottom)); 
  right: 16px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  z-index: 1001;
  align-items: flex-end; /* Alinea botones a la derecha */
}

.offers-fab {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: #fee715;
  color: #000;
  border: none;
  box-shadow: 0 4px 10px rgba(0,0,0,0.3);
  position: relative;
}

.offers-badge {
  position: absolute;
  top: -5px; right: -5px;
  background: #f44336;
  color: white;
  padding: 2px 6px;
  border-radius: 10px;
  border: 2px solid #fff;
}

.location-btn-smart {
  background: var(--header-bg);
  backdrop-filter: blur(20px);
  border: 1px solid var(--border-color);
  height: 50px;
  border-radius: 25px;
  color: var(--active-color);
  box-shadow: var(--shadow);
  padding: 0 13px;
  transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 50px; /* Default circular */
  overflow: hidden;
}

.location-btn-smart.moved {
  width: auto; /* Expand for text */
  padding: 0 20px;
  background: var(--active-color);
  color: #000;
  border-color: #000;
}

.btn-content {
  display: flex;
  align-items: center;
  gap: 10px;
  white-space: nowrap;
}

.btn-text {
  font-size: 0.85rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.fade-scale-enter-active,
.fade-scale-leave-active {
  transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.fade-scale-enter-from,
.fade-scale-leave-to {
  opacity: 0;
  transform: scale(0.5) translateY(20px);
}

.promo-modal-overlay {
  position: fixed;
  top: 0; left: 0; width: 100%; height: 100%;
  background: rgba(0,0,0,0.8);
  z-index: 4000;
  display: flex; align-items: center; justify-content: center;
}

.promo-modal-content {
  background: var(--card-bg); width: 90%; max-width: 450px;
  border-radius: 24px; overflow: hidden;
  box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}

.promo-header-modal { position: relative; height: 200px; }
.promo-img-modal { width: 100%; height: 100%; object-fit: cover; }
.promo-badge-modal { position: absolute; bottom: 0; left: 0; background: #EAB308; color: #000; padding: 5px 15px; font-weight: 800; border-top-right-radius: 12px; }
.promo-body-modal { padding: 25px; }
.promo-title-modal { font-size: 1.5rem; font-weight: 800; margin-bottom: 10px; }
.promo-biz { color: var(--active-color); font-weight: 700; margin-bottom: 15px; }
.promo-actions-modal { padding: 0 25px 25px; }
.business-detail-btn-modal { width: 100%; background: var(--active-color); color: #000; border: none; padding: 15px; border-radius: 12px; font-weight: 800; cursor: pointer; }

.modal-fade-enter-active, .modal-fade-leave-active { transition: opacity 0.3s ease; }
.modal-fade-enter-from, .modal-fade-leave-to { opacity: 0; }

.pulse { animation: pulse-animation 2s infinite; }
@keyframes pulse-animation {
  0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(254, 231, 21, 0.7); }
  70% { transform: scale(1.1); box-shadow: 0 0 0 15px rgba(254, 231, 21, 0); }
  100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(254, 231, 21, 0); }
}

@media (max-width: 600px) {
  .map-floating-controls { 
    bottom: calc(100px + var(--safe-area-bottom)); 
  }
}
</style>
