<template>
  <Stack gap="6">
    <PageHeader :title="t('profileAddresses.form.title_edit')" />

    <Card v-if="isLoadingAddress" padding="lg">
      <Stack align="center" gap="3">
        <Spinner />
        <Text tone="muted">{{ t('profileAddresses.states.loading') }}</Text>
      </Stack>
    </Card>

    <Stack v-else-if="addressData" gap="4">
      <Input
        v-model="addressData.name"
        :label="t('profileAddresses.form.name.label')"
        :placeholder="t('profileAddresses.form.name.placeholder')"
      />

      <!-- Address search with Mapbox -->
      <div class="form-control">
        <label class="label">
          <span class="label-text">{{ t('profileAddresses.form.address.label') }}</span>
        </label>
        <div ref="searchBoxContainer" class="w-full" />
        <input
          v-if="addressData.address"
          type="hidden"
          :value="addressData.address"
        />
      </div>

      <!-- Mapbox map for selecting coordinates -->
      <div class="form-control">
        <label class="label">
          <span class="label-text">{{ t('profileAddresses.form.mapLabel') }}</span>
        </label>
        <div class="h-80 rounded-lg overflow-hidden border border-base-300">
          <MapboxMap
            ref="mapComponentRef"
            :map-id="'address-picker-edit'"
            style="width: 100%; height: 100%"
            :options="{
              style: 'mapbox://styles/mapbox/streets-v12',
              center: [addressData.longitude || 37.6173, addressData.latitude || 55.7558],
              zoom: 12
            }"
            @mb-click="onMapClick"
            @mb-created="onMapCreated"
          >
            <MapboxDefaultMarker
              v-if="addressData.latitude && addressData.longitude"
              :marker-id="'selected-location'"
              :lnglat="[addressData.longitude, addressData.latitude]"
              color="#3b82f6"
            />
          </MapboxMap>
        </div>
        <label class="label" v-if="addressData.latitude && addressData.longitude">
          <span class="label-text-alt text-success">
            {{ addressData.latitude.toFixed(6) }}, {{ addressData.longitude.toFixed(6) }}
          </span>
        </label>
      </div>

      <Stack direction="row" gap="3">
        <Button @click="updateAddress" :disabled="isSaving || !addressData.latitude">
          {{ isSaving ? t('profileAddresses.form.updating') : t('profileAddresses.form.update') }}
        </Button>
        <Button variant="outline" :as="NuxtLink" :to="localePath('/clientarea/addresses')">
          {{ t('common.cancel') }}
        </Button>
      </Stack>

      <!-- Delete button -->
      <div class="pt-4 border-t border-base-300">
        <Button variant="ghost" class="text-error" @click="handleDelete" :disabled="isDeleting">
          <Icon name="lucide:trash-2" size="16" class="mr-2" />
          {{ isDeleting ? t('profileAddresses.actions.deleting') : t('profileAddresses.actions.delete') }}
        </Button>
      </div>
    </Stack>

    <EmptyState
      v-else
      icon="lucide:alert-circle"
      :title="t('profileAddresses.error.not_found')"
      :action-label="t('profileAddresses.error.back_to_list')"
      :action-to="localePath('/clientarea/addresses')"
    />
  </Stack>
</template>

<script setup lang="ts">
import { NuxtLink } from '#components'
import type { MapMouseEvent, Map as MapboxMapType } from 'mapbox-gl'

interface MapboxSearchBox {
  value: string
}

definePageMeta({
  layout: 'topnav',
  middleware: ['auth-oidc']
})

const route = useRoute()
const { execute, mutate } = useGraphQL()
const { t } = useI18n()
const localePath = useLocalePath()
const config = useRuntimeConfig()

const uuid = computed(() => route.params.uuid as string)

const isLoadingAddress = ref(true)
const isSaving = ref(false)
const isDeleting = ref(false)
const searchBoxContainer = ref<HTMLElement | null>(null)
const mapInstance = ref<MapboxMapType | null>(null)
const searchBoxRef = ref<MapboxSearchBox | null>(null)

const addressData = ref<{
  uuid: string
  name: string
  address: string
  latitude: number | null
  longitude: number | null
  countryCode: string | null
} | null>(null)

// Load address data
const loadAddress = async () => {
  isLoadingAddress.value = true
  try {
    const { GetTeamAddressesDocument } = await import('~/composables/graphql/team/teams-generated')
    const data = await execute(GetTeamAddressesDocument, {}, 'team', 'teams')
    const addresses = data?.teamAddresses || []
    const found = addresses.find((a) => a?.uuid === uuid.value)

    if (found) {
      addressData.value = {
        uuid: found.uuid,
        name: found.name || '',
        address: found.address || '',
        latitude: found.latitude ?? null,
        longitude: found.longitude ?? null,
        countryCode: found.countryCode ?? null
      }
    }
  } catch (e) {
    console.error('Failed to load address', e)
  } finally {
    isLoadingAddress.value = false
  }
}

await loadAddress()

const onMapCreated = (map: MapboxMapType) => {
  mapInstance.value = map
}

// Reverse geocode: get address by coordinates (local language)
const reverseGeocode = async (lat: number, lng: number): Promise<{ address: string | null; countryCode: string | null }> => {
  try {
    const token = config.public.mapboxAccessToken
    const response = await fetch(
      `https://api.mapbox.com/geocoding/v5/mapbox.places/${lng},${lat}.json?access_token=${token}`
    )
    const data = await response.json()
    const feature = data.features?.[0]
    if (!feature) return { address: null, countryCode: null }

    // Extract country code from context
    const countryContext = feature.context?.find((c: { id?: string }) => c.id?.startsWith('country.'))
    const countryCode = countryContext?.short_code?.toUpperCase() || null

    return { address: feature.place_name, countryCode }
  } catch {
    return { address: null, countryCode: null }
  }
}

const onMapClick = async (event: MapMouseEvent) => {
  if (!addressData.value) return

  const lat = event.lngLat.lat
  const lng = event.lngLat.lng

  addressData.value.latitude = lat
  addressData.value.longitude = lng

  // Reverse geocode: load address by coordinates
  const result = await reverseGeocode(lat, lng)
  if (result.address) {
    addressData.value.address = result.address
    addressData.value.countryCode = result.countryCode
    // Update SearchBox input
    if (searchBoxRef.value) {
      searchBoxRef.value.value = result.address
    }
  }
}

// Initialize Mapbox SearchBox
onMounted(async () => {
  if (!searchBoxContainer.value) return

  const { MapboxSearchBox } = await import('@mapbox/search-js-web')

  const searchBox = new MapboxSearchBox()
  searchBox.accessToken = config.public.mapboxAccessToken as string
  searchBox.options = {
    // Without language: uses local country language
  }
  searchBox.placeholder = t('profileAddresses.form.address.placeholder')

  // Pre-fill with existing address
  if (addressData.value?.address) {
    searchBox.value = addressData.value.address
  }

  searchBox.addEventListener('retrieve', (event: CustomEvent) => {
    if (!addressData.value) return

    const feature = event.detail.features?.[0]
    if (feature) {
      const [lng, lat] = feature.geometry.coordinates
      addressData.value.address = feature.properties.full_address || feature.properties.name
      addressData.value.latitude = lat
      addressData.value.longitude = lng

      // Extract country code from context
      const countryContext = feature.properties.context?.country
      addressData.value.countryCode = countryContext?.country_code?.toUpperCase() || null

      // Fly to selected location
      if (mapInstance.value) {
        mapInstance.value.flyTo({
          center: [lng, lat],
          zoom: 15
        })
      }
    }
  })

  searchBoxRef.value = searchBox
  searchBoxContainer.value.appendChild(searchBox as unknown as Node)
})

const updateAddress = async () => {
  if (!addressData.value || !addressData.value.name || !addressData.value.address || !addressData.value.latitude) return

  isSaving.value = true
  try {
    const { UpdateTeamAddressDocument } = await import('~/composables/graphql/team/teams-generated')
    const result = await mutate(UpdateTeamAddressDocument, {
      input: {
        uuid: addressData.value.uuid,
        name: addressData.value.name,
        address: addressData.value.address,
        latitude: addressData.value.latitude,
        longitude: addressData.value.longitude,
        countryCode: addressData.value.countryCode
      }
    }, 'team', 'teams')

    if (result.updateTeamAddress?.success) {
      navigateTo(localePath('/clientarea/addresses'))
    } else {
      console.error('Failed to update address:', result.updateTeamAddress?.message)
    }
  } catch (e) {
    console.error('Failed to update address', e)
  } finally {
    isSaving.value = false
  }
}

const handleDelete = async () => {
  if (!addressData.value) return
  if (!confirm(t('profileAddresses.actions.confirm_delete'))) return

  isDeleting.value = true
  try {
    const { DeleteTeamAddressDocument } = await import('~/composables/graphql/team/teams-generated')
    const result = await mutate(DeleteTeamAddressDocument, { uuid: addressData.value.uuid }, 'team', 'teams')

    if (result.deleteTeamAddress?.success) {
      navigateTo(localePath('/clientarea/addresses'))
    } else {
      console.error('Failed to delete address:', result.deleteTeamAddress?.message)
    }
  } catch (e) {
    console.error('Failed to delete address', e)
  } finally {
    isDeleting.value = false
  }
}
</script>

<style>
/* Mapbox SearchBox styling */
mapbox-search-box {
  width: 100%;
}

mapbox-search-box::part(input) {
  height: 3rem;
  padding: 0.5rem 1rem;
  font-size: 1rem;
  border: 1px solid oklch(var(--bc) / 0.2);
  border-radius: var(--rounded-btn, 0.5rem);
  background-color: oklch(var(--b1));
  color: oklch(var(--bc));
}

mapbox-search-box::part(input):focus {
  outline: 2px solid oklch(var(--p));
  outline-offset: 2px;
}

mapbox-search-box::part(results-list) {
  background-color: oklch(var(--b1));
  border: 1px solid oklch(var(--bc) / 0.2);
  border-radius: var(--rounded-btn, 0.5rem);
  margin-top: 0.25rem;
}

mapbox-search-box::part(result-item) {
  padding: 0.75rem 1rem;
  color: oklch(var(--bc));
}

mapbox-search-box::part(result-item):hover {
  background-color: oklch(var(--b2));
}
</style>
