<template>
  <div>
    <!-- Add button -->
    <div class="mb-4">
      <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>
    </div>

    <!-- 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>

    <!-- List content -->
    <div v-else-if="isLoading" class="flex items-center justify-center py-8">
      <Card padding="lg">
        <Stack align="center" justify="center" gap="3">
          <Spinner />
          <Text tone="muted">{{ t('clientOffersList.states.loading') }}</Text>
        </Stack>
      </Card>
    </div>

    <template v-else>
      <Stack gap="3">
        <div
          v-for="offer in displayItems"
          :key="offer.uuid"
          :class="{ 'ring-2 ring-primary rounded-lg': offer.uuid === selectedOfferId }"
          @click="onSelectOffer(offer)"
          @mouseenter="hoveredOfferId = offer.uuid"
          @mouseleave="hoveredOfferId = undefined"
        >
          <Card padding="lg">
            <Stack gap="3">
              <Stack direction="row" justify="between" align="center">
                <Heading :level="3">{{ offer.productName || t('clientOffersList.labels.untitled') }}</Heading>
                <Badge :variant="getStatusVariant(offer.status)">
                  {{ getStatusText(offer.status) }}
                </Badge>
              </Stack>

              <Text v-if="offer.categoryName" tone="muted">{{ offer.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">{{ offer.quantity }} {{ offer.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(offer.pricePerUnit, offer.currency) }}</Text>
                </Stack>

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

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

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

      <Stack v-if="displayItems.length === 0" align="center" gap="2" class="py-8">
        <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"
        />
      </Stack>
    </template>
  </div>
</template>

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

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

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

const { execute } = useGraphQL()
const PAGE_SIZE = 24
const offers = ref<any[]>([])
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 onBoundsChange = (bounds: MapBounds) => {
  currentBounds.value = bounds
}

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
    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
  })
})

// Hovered item with coordinates for map highlight
const hoveredItem = computed(() => {
  if (!hoveredOfferId.value) return null
  const item = offers.value.find(i => i.uuid === hoveredOfferId.value)
  if (!item?.locationLatitude || !item?.locationLongitude) return null
  return { latitude: Number(item.locationLatitude), longitude: Number(item.locationLongitude) }
})

// 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: any) => {
  selectedOfferId.value = offer.uuid
  navigateTo(localePath(`/clientarea/offers/${offer.uuid}`))
}

// Handle selection from map
const onMapSelect = (uuid: string) => {
  const offer = offers.value.find(i => i.uuid === uuid)
  if (offer) {
    selectedOfferId.value = uuid
    navigateTo(localePath(`/clientarea/offers/${uuid}`))
  }
}

// Filter component for the layout
const SellerOffersFilterComponent = defineComponent({
  setup() {
    return () => h('div', { class: 'p-2 space-y-3' }, [
      h('div', {}, [
        h('div', { class: 'text-xs font-semibold mb-1 text-base-content/70' }, t('clientOffersList.filters.status_label')),
        h('ul', { class: 'menu menu-compact' },
          statusFilters.value.map(filter =>
            h('li', { key: filter.id },
              h('a', {
                class: selectedStatus.value === filter.id ? 'active' : '',
                onClick: () => { selectedStatus.value = filter.id }
              }, filter.label)
            )
          )
        )
      ])
    ])
  }
})

// Provide data to layout
provideCatalogLayout({
  // Custom subnav for seller clientarea
  subNavItems: [
    { label: t('cabinetNav.myOffers'), path: '/clientarea/offers' },
  ],
  searchQuery,
  activeFilters: activeFilterBadges,
  displayedCount: computed(() => displayItems.value.length),
  totalCount: computed(() => totalOffers.value),
  onSearch,
  onRemoveFilter,
  filterComponent: SellerOffersFilterComponent,
  mapItems: itemsWithCoords,
  mapId: 'seller-offers-map',
  pointColor: '#f59e0b',
  hoveredItemId: hoveredOfferId,
  hoveredItem,
  onMapSelect,
  onBoundsChange,
  searchWithMap
})

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 || []
  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>
