<template>
  <CatalogPage
    :items="displayItems"
    :map-items="itemsWithCoords"
    :loading="isLoading"
    with-map
    map-id="seller-offers-map"
    point-color="#f59e0b"
    :selected-id="selectedOfferId"
    :hovered-id="hoveredOfferId"
    :total-count="totalOffers"
    @select="onSelectOffer"
    @update:hovered-id="hoveredOfferId = $event"
  >
    <template #searchBar="{ displayedCount, totalCount }">
      <CatalogSearchBar
        v-model:search-query="searchQuery"
        :active-filters="activeFilterBadges"
        :displayed-count="displayedCount"
        :total-count="totalCount"
        @remove-filter="onRemoveFilter"
        @search="onSearch"
      >
        <template #filters>
          <div class="p-2 space-y-3">
            <div>
              <div class="text-xs font-semibold mb-1 text-base-content/70">{{ t('clientOffersList.filters.status_label') }}</div>
              <ul class="menu menu-compact">
                <li v-for="filter in statusFilters" :key="filter.id">
                  <a
                    :class="{ 'active': selectedStatus === filter.id }"
                    @click="selectedStatus = filter.id"
                  >{{ filter.label }}</a>
                </li>
              </ul>
            </div>
          </div>
        </template>
      </CatalogSearchBar>
    </template>

    <template #header>
      <!-- Error state -->
      <Alert v-if="hasError" variant="error" class="mb-4">
        <Stack gap="2">
          <Heading :level="4" weight="semibold">{{ t('clientOffersList.error.title') }}</Heading>
          <Text tone="muted">{{ error }}</Text>
          <Button @click="loadOffers">{{ t('clientOffersList.error.retry') }}</Button>
        </Stack>
      </Alert>

      <!-- Add button -->
      <NuxtLink :to="localePath('/clientarea/offers/new')">
        <Button class="w-full">
          <Icon name="lucide:plus" size="16" class="mr-2" />
          {{ t('clientOffersList.actions.add') }}
        </Button>
      </NuxtLink>
    </template>

    <template #card="{ item }">
      <Card padding="lg">
        <Stack gap="3">
          <Stack direction="row" justify="between" align="center">
            <Heading :level="3">{{ item.productName || t('clientOffersList.labels.untitled') }}</Heading>
            <Badge :variant="getStatusVariant(item.status)">
              {{ getStatusText(item.status) }}
            </Badge>
          </Stack>

          <Text v-if="item.categoryName" tone="muted">{{ item.categoryName }}</Text>

          <Grid :cols="1" :md="4" :gap="3">
            <Stack gap="1">
              <Text size="sm" tone="muted">{{ t('clientOffersList.labels.quantity') }}</Text>
              <Text weight="semibold">{{ item.quantity }} {{ item.unit || t('search.units.tons_short') }}</Text>
            </Stack>

            <Stack gap="1">
              <Text size="sm" tone="muted">{{ t('clientOffersList.labels.price') }}</Text>
              <Text weight="semibold">{{ formatPrice(item.pricePerUnit, item.currency) }}</Text>
            </Stack>

            <Stack gap="1">
              <Text size="sm" tone="muted">{{ t('clientOffersList.labels.location') }}</Text>
              <Text>{{ item.locationName || t('clientOffersList.labels.not_specified') }}</Text>
            </Stack>

            <Stack gap="1">
              <Text size="sm" tone="muted">{{ t('clientOffersList.labels.valid_until') }}</Text>
              <Text>{{ formatDate(item.validUntil) }}</Text>
            </Stack>
          </Grid>
        </Stack>
      </Card>
    </template>

    <template #pagination>
      <PaginationLoadMore
        v-if="offers.length > 0"
        :shown="offers.length"
        :total="totalOffers"
        :can-load-more="canLoadMore"
        :loading="isLoadingMore"
        @load-more="loadMore"
        class="mt-4"
      />
    </template>

    <template #empty>
      <EmptyState
        icon="🏷️"
        :title="t('clientOffersList.empty.title')"
        :description="t('clientOffersList.empty.subtitle')"
        :action-label="t('clientOffersList.actions.addOffer')"
        :action-to="localePath('/clientarea/offers/new')"
        action-icon="lucide:plus"
      />
    </template>
  </CatalogPage>
</template>

<script setup lang="ts">
import type { MapBounds } from '~/components/catalog/CatalogMap.vue'
import { GetOffersDocument, type GetOffersQueryResult } from '~/composables/graphql/public/exchange-generated'

type Offer = NonNullable<NonNullable<GetOffersQueryResult['getOffers']>[number]>

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

const localePath = useLocalePath()
const { t, locale } = useI18n()
const { activeTeamId } = useActiveTeam()

const { execute } = useGraphQL()
const PAGE_SIZE = 24
const offers = ref<Offer[]>([])
const totalOffers = ref(0)
const isLoadingMore = ref(false)

const selectedOfferId = ref<string>()
const hoveredOfferId = ref<string>()

// Search bar
const searchQuery = ref('')

// Search with map checkbox
const searchWithMap = ref(false)
const currentBounds = ref<MapBounds | null>(null)

const {
  data: offersData,
  pending: offersPending,
  error: loadError,
  refresh: refreshOffers
} = await useServerQuery(
  'client-offers-list',
  GetOffersDocument,
  { teamUuid: activeTeamId.value || null, limit: PAGE_SIZE, offset: 0 },
  'public',
  'exchange'
)

watchEffect(() => {
  if (offersData.value?.getOffers) {
    offers.value = offersData.value.getOffers.filter((o): o is Offer => o !== null)
    totalOffers.value = offersData.value.getOffersCount ?? offersData.value.getOffers.length
  }
})

const isLoading = computed(() => offersPending.value && offers.value.length === 0)
const canLoadMore = computed(() => offers.value.length < totalOffers.value)
const hasError = computed(() => !!loadError.value)
const error = computed(() => loadError.value?.message || t('clientOffersList.error.load'))

// Map items with coordinates
const itemsWithCoords = computed(() =>
  offers.value.filter(item =>
    item.locationLatitude != null &&
    item.locationLongitude != null &&
    !isNaN(Number(item.locationLatitude)) &&
    !isNaN(Number(item.locationLongitude))
  ).map(item => ({
    uuid: item.uuid,
    name: item.productName || '',
    latitude: Number(item.locationLatitude),
    longitude: Number(item.locationLongitude)
  }))
)

// Filtered items when searchWithMap is enabled
const displayItems = computed(() => {
  if (!searchWithMap.value || !currentBounds.value) return offers.value
  return offers.value.filter(item => {
    if (item.locationLatitude == null || item.locationLongitude == null) return false
    const { west, east, north, south } = currentBounds.value!
    const lng = Number(item.locationLongitude)
    const lat = Number(item.locationLatitude)
    return lng >= west && lng <= east && lat >= south && lat <= north
  })
})

// Active filter badges (status filter)
const selectedStatus = ref<string>('all')
const statusFilters = computed(() => [
  { id: 'all', label: t('clientOffersList.filters.all') },
  { id: 'active', label: t('clientOffersList.status.active') },
  { id: 'draft', label: t('clientOffersList.status.draft') },
  { id: 'expired', label: t('clientOffersList.status.expired') },
])

const activeFilterBadges = computed(() => {
  const badges: { id: string; label: string }[] = []
  if (selectedStatus.value && selectedStatus.value !== 'all') {
    const filter = statusFilters.value.find(f => f.id === selectedStatus.value)
    if (filter) badges.push({ id: `status:${filter.id}`, label: filter.label })
  }
  return badges
})

// Remove filter badge
const onRemoveFilter = (id: string) => {
  if (id.startsWith('status:')) {
    selectedStatus.value = 'all'
  }
}

// Search handler
const onSearch = () => {
  // TODO: Implement search
}

const onSelectOffer = (offer: { uuid?: string | null }) => {
  if (offer.uuid) {
    selectedOfferId.value = offer.uuid
    navigateTo(localePath(`/clientarea/offers/${offer.uuid}`))
  }
}

const getStatusVariant = (status: string) => {
  const variants: Record<string, string> = {
    active: 'success',
    draft: 'warning',
    expired: 'error',
    sold: 'muted'
  }
  return variants[status] || 'muted'
}

const getStatusText = (status: string) => {
  const texts: Record<string, string> = {
    active: t('clientOffersList.status.active'),
    draft: t('clientOffersList.status.draft'),
    expired: t('clientOffersList.status.expired'),
    sold: t('clientOffersList.status.sold')
  }
  return texts[status] || status || t('clientOffersList.status.unknown')
}

const formatDate = (date: string) => {
  if (!date) return t('clientOffersList.labels.not_specified')
  try {
    const dateObj = new Date(date)
    if (isNaN(dateObj.getTime())) return t('clientOffersList.labels.invalid_date')
    return new Intl.DateTimeFormat(locale.value === 'ru' ? 'ru-RU' : 'en-US', {
      day: 'numeric',
      month: 'long',
      year: 'numeric'
    }).format(dateObj)
  } catch {
    return t('clientOffersList.labels.invalid_date')
  }
}

const formatPrice = (price: number | string | null | undefined, currency?: string | null) => {
  if (!price) return t('clientOffersList.labels.not_specified')
  const num = typeof price === 'string' ? parseFloat(price) : price
  const curr = currency || 'USD'
  try {
    return new Intl.NumberFormat(locale.value === 'ru' ? 'ru-RU' : 'en-US', {
      style: 'currency',
      currency: curr,
      maximumFractionDigits: 0
    }).format(num)
  } catch {
    return `${num} ${curr}`
  }
}

const fetchOffers = async (offset = 0, replace = false) => {
  const data = await execute(
    GetOffersDocument,
    { teamUuid: activeTeamId.value || null, limit: PAGE_SIZE, offset },
    'public',
    'exchange'
  )
  const next = (data?.getOffers || []).filter((o): o is Offer => o !== null)
  offers.value = replace ? next : offers.value.concat(next)
  totalOffers.value = data?.getOffersCount ?? totalOffers.value
}

const loadOffers = async () => refreshOffers()
const loadMore = async () => {
  if (isLoadingMore.value) return
  isLoadingMore.value = true
  try {
    await fetchOffers(offers.value.length)
  } finally {
    isLoadingMore.value = false
  }
}

watch(
  () => activeTeamId.value,
  async () => {
    await fetchOffers(0, true)
  }
)
</script>
