<template>
  <q-page class="location-map-page">
    <div ref="mapRef" class="location-map-container" />

    <q-btn
      flat
      round
      color="white"
      icon="mdi-arrow-left"
      class="location-map-back-btn"
      @click="handleBack"
    />

    <div class="location-map-bottom-card">
      <p class="font14 fontbold">{{ $t('common.terms.address') }}</p>
      <q-input
        :model-value="currentAddress"
        outlined
        dense
        readonly
        class="location-map-address-input q-mb-md"
        bg-color="white"
        input-class="text-text"
        :loading="reversing"
        :placeholder="reversing ? '' : $t('auth.geocoding_failed_short')"
      />
      <q-btn
        color="primary-button"
        :label="$t('auth.confirm_location')"
        rounded
        padding="14px 16px"
        class="full-width"
        :loading="reversing"
        :disable="!currentGeoData"
        @click="handleConfirm"
      />
    </div>
  </q-page>
</template>

<script setup>
import { ref, nextTick, onMounted, onUnmounted } from 'vue';
import { useRouter } from 'vue-router';
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
import { GoogleMap } from '@capacitor/google-maps';
import { useRegistrationFlowStore } from 'src/stores/registrationFlow';
import { useGeocodingApi } from 'src/composables/useGeocodingApi';

const router = useRouter();
const $q = useQuasar();
const { t } = useI18n();
const flowStore = useRegistrationFlowStore();
const { reverseGeocode } = useGeocodingApi();

const mapRef = ref(null);
const reversing = ref(false);
const currentAddress = ref('');
const currentLat = ref(null);
const currentLng = ref(null);
const currentGeoData = ref(null);

let googleMap = null;
const markerId = ref(null);

const transparentEls = [];

const applyMapTransparency = () => {
  [document.documentElement, document.body, document.getElementById('q-app')]
    .filter(Boolean)
    .forEach((el) => {
      el.style.setProperty('background', 'transparent', 'important');
      transparentEls.push(el);
    });
};

const removeMapTransparency = () => {
  transparentEls.forEach((el) => el.style.removeProperty('background'));
  transparentEls.length = 0;
};

const waitForStableBounds = async (el) => {
  let previous = -1;

  for (let i = 0; i < 12; i += 1) {
    const { height } = el.getBoundingClientRect();
    if (height > 0 && height === previous) return;
    previous = height;
    await new Promise((resolve) => setTimeout(resolve, 50));
  }
};

const handleBack = async () => {
  removeMapTransparency();
  await destroyMap();
  router.back();
};

const handleConfirm = async () => {
  if (!currentGeoData.value) return;
  flowStore.setConfirmedLocation(currentGeoData.value);
  removeMapTransparency();
  await destroyMap();
  router.push({ name: 'AddressCompletionPage' });
};

const destroyMap = async () => {
  if (googleMap) {
    await googleMap.destroy();
    googleMap = null;
  }
};

const updateMarkerPosition = async (lat, lng) => {
  reversing.value = true;
  try {
    const geoData = await reverseGeocode(lat, lng);
    if (geoData) {
      currentGeoData.value = { ...geoData, lat, lng };
      const parts = [geoData.address, geoData.number, geoData.district, geoData.city, geoData.state].filter(Boolean);
      currentAddress.value = parts.join(', ');
    } else {
      currentGeoData.value = { lat, lng, address: '', number: '', district: '', city: '', state: '', zip_code: '' };
      currentAddress.value = '';
      $q.notify({ type: 'warning', message: t('auth.geocoding_failed') });
    }
  } catch {
    currentGeoData.value = { lat, lng, address: '', number: '', district: '', city: '', state: '', zip_code: '' };
    currentAddress.value = '';
    $q.notify({ type: 'warning', message: t('auth.geocoding_failed') });
  } finally {
    reversing.value = false;
  }
};

const moveMarkerTo = async (lat, lng) => {
  if (markerId.value) {
    await googleMap.removeMarker(markerId.value);
  }
  markerId.value = await googleMap.addMarker({
    coordinate: { lat, lng },
    draggable: true,
  });
};

onMounted(async () => {
  if (!flowStore.hasInitialLocation()) {
    router.replace({ name: 'LoginPage' });
    return;
  }

  const lat = flowStore.initialLat;
  const lng = flowStore.initialLng;
  currentLat.value = lat;
  currentLng.value = lng;

  applyMapTransparency();
  await nextTick();
  await waitForStableBounds(mapRef.value);

  const apiKey = process.env.GOOGLE_MAPS_API_KEY;

  if (!apiKey) {
    $q.notify({ type: 'negative', message: t('auth.map_unavailable') });
    return;
  }

  try {
    googleMap = await GoogleMap.create({
      id: 'location-map',
      element: mapRef.value,
      apiKey,
      config: {
        center: { lat, lng },
        zoom: 17,
      },
    });
  } catch (error) {
    console.error('Failed to create map', error);
    $q.notify({ type: 'negative', message: t('auth.map_unavailable') });
    return;
  }

  markerId.value = await googleMap.addMarker({
    coordinate: { lat, lng },
    draggable: true,
  });

  await updateMarkerPosition(lat, lng);

  await googleMap.setOnMarkerDragEndListener(async (event) => {
    const { latitude, longitude } = event;
    currentLat.value = latitude;
    currentLng.value = longitude;
    await updateMarkerPosition(latitude, longitude);
  });

  await googleMap.setOnMapClickListener(async (event) => {
    const { latitude, longitude } = event;
    currentLat.value = latitude;
    currentLng.value = longitude;
    await moveMarkerTo(latitude, longitude);
    await updateMarkerPosition(latitude, longitude);
  });
});

onUnmounted(async () => {
  removeMapTransparency();
  await destroyMap();
});
</script>

<style lang="scss" scoped>
.location-map-page {
  position: relative;
  width: 100vw;
  height: 100dvh;
  overflow: hidden;
  background: transparent;
}

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

.location-map-back-btn {
  position: absolute;
  top: calc(16px + env(safe-area-inset-top));
  left: 16px;
  z-index: 10;
  background: rgba(0, 0, 0, 0.4);
  border-radius: 50%;
}

.location-map-bottom-card {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 10;
  background: white;
  border-radius: 24px 24px 0 0;
  padding: 20px 20px calc(20px + env(safe-area-inset-bottom));
  box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.12);
}

.location-map-address-label {
  color: var(--q-text);
  margin: 0 0 8px;
}

.location-map-address-input {
  border-radius: 8px;
}
</style>
