<script setup lang="ts">
import { ref, watch, onBeforeUnmount, nextTick, computed } from 'vue'
import { getCachedImageUrl, revokeAllImageUrls } from '@/common/imageCache'

const props = defineProps<{
  title: string
  fetchBaseUrl: string
  ids?: readonly string[]
  itemKey: string
  imageFields?: readonly string[]
  isParentAuthenticated?: boolean
  filterFn?: (item: any) => boolean
  getItemClass?: (item: any) => string | string[] | Record<string, boolean>
}>()

// Compute the fetch URL with ids if present
const fetchUrl = computed(() => {
  if (props.ids && props.ids.length > 0) {
    const separator = props.fetchBaseUrl.includes('?') ? '&' : '?'
    return `${props.fetchBaseUrl}${separator}ids=${props.ids.join(',')}`
  }
  return props.fetchBaseUrl
})

const emit = defineEmits<{
  (e: 'trigger-item', item: any): void
}>()

const items = ref<any[]>([])
const loading = ref(true)
const error = ref<string | null>(null)
const scrollWrapper = ref<HTMLDivElement | null>(null)
const itemRefs = ref<Record<string, HTMLElement | Element | null>>({})
const lastCenteredItemId = ref<string | null>(null)
const readyItemId = ref<string | null>(null)

const fetchItems = async () => {
  loading.value = true
  error.value = null

  try {
    const resp = await fetch(fetchUrl.value)
    if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
    const data = await resp.json()
    // Try to use 'tasks', 'reward_status', or 'items' as fallback
    let itemList = data[props.itemKey || 'items'] || []
    if (props.filterFn) itemList = itemList.filter(props.filterFn)
    items.value = itemList
    // Fetch images for each item
    await Promise.all(
      itemList.map(async (item: any) => {
        if (props.imageFields) {
          for (const field of props.imageFields) {
            if (item[field]) {
              try {
                item[`${field.replace('_id', '_url')}`] = await getCachedImageUrl(item[field])
              } catch {
                item[`${field.replace('_id', '_url')}`] = null
              }
            }
          }
        } else if (item.image_id) {
          try {
            item.image_url = await getCachedImageUrl(item.image_id)
          } catch {
            console.error('Error fetching image for item', item.id)
            item.image_url = null
          }
        }
      }),
    )
  } catch (err) {
    error.value = err instanceof Error ? err.message : 'Failed to fetch items'
    items.value = []
    console.error('Error fetching items:', err)
  } finally {
    loading.value = false
  }
}

async function refresh() {
  await fetchItems()
  loading.value = false
}

defineExpose({
  refresh,
  items,
})

const centerItem = async (itemId: string) => {
  await nextTick()
  const wrapper = scrollWrapper.value
  const card = itemRefs.value[itemId]
  if (wrapper && card) {
    const wrapperRect = wrapper.getBoundingClientRect()
    const cardRect = card.getBoundingClientRect()
    const wrapperScrollLeft = wrapper.scrollLeft
    const cardCenter = cardRect.left + cardRect.width / 2
    const wrapperCenter = wrapperRect.left + wrapperRect.width / 2
    const scrollOffset = cardCenter - wrapperCenter
    wrapper.scrollTo({
      left: wrapperScrollLeft + scrollOffset,
      behavior: 'smooth',
    })
  }
}

const handleClicked = async (item: any) => {
  await nextTick()
  const wrapper = scrollWrapper.value
  const card = itemRefs.value[item.id]
  if (!wrapper || !card) return

  const wrapperRect = wrapper.getBoundingClientRect()
  const cardRect = card.getBoundingClientRect()
  const cardCenter = cardRect.left + cardRect.width / 2
  const cardFullyVisible = cardCenter >= wrapperRect.left && cardCenter <= wrapperRect.right

  if (!cardFullyVisible || lastCenteredItemId.value !== item.id) {
    // Center the item, but don't trigger
    await centerItem(item.id)
    lastCenteredItemId.value = item.id
    readyItemId.value = item.id
    return
  }
  emit(
    'trigger-item',
    items.value.find((i) => i.id === item.id),
  )
  readyItemId.value = null
}

watch(
  () => [props.ids],
  () => {
    fetchItems()
  },
  { immediate: true },
)

onBeforeUnmount(() => {
  revokeAllImageUrls()
})
</script>

<template>
  <div class="child-list-container">
    <h3>{{ title }}</h3>

    <div v-if="loading" class="loading">Loading...</div>
    <div v-else-if="error" class="error">Error: {{ error }}</div>
    <div v-else-if="items.length === 0" class="empty">No {{ title }}</div>
    <div v-else class="scroll-wrapper" ref="scrollWrapper">
      <div class="item-scroll">
        <div
          v-for="item in items"
          :key="item.id"
          :class="['item-card', props.getItemClass?.(item)]"
          :ref="(el) => (itemRefs[item.id] = el)"
          @click.stop="handleClicked(item)"
        >
          <slot name="item" :item="item">
            <div class="item-name">{{ item.name }}</div>
          </slot>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.child-list-container {
  background: var(--child-list-bg, rgba(255, 255, 255, 0.1));
  border-radius: 12px;
  padding: 1rem;
  color: var(--child-list-title-color, #fff);
  width: 100%;
  box-sizing: border-box;
}
.scroll-wrapper {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: smooth;
  width: 100%;
  -webkit-overflow-scrolling: touch;
}

.scroll-wrapper::-webkit-scrollbar {
  height: 8px;
}

.scroll-wrapper::-webkit-scrollbar-track {
  background: var(--child-list-scrollbar-track, rgba(255, 255, 255, 0.05));
  border-radius: 10px;
}

.scroll-wrapper::-webkit-scrollbar-thumb {
  background: var(
    --child-list-scrollbar-thumb,
    linear-gradient(180deg, rgba(102, 126, 234, 0.8), rgba(118, 75, 162, 0.8))
  );
  border-radius: 10px;
  border: var(--child-list-scrollbar-thumb-border, 2px solid rgba(255, 255, 255, 0.08));
}

.scroll-wrapper::-webkit-scrollbar-thumb:hover {
  background: var(
    --child-list-scrollbar-thumb-hover,
    linear-gradient(180deg, rgba(102, 126, 234, 1), rgba(118, 75, 162, 1))
  );
  box-shadow: 0 0 8px rgba(102, 126, 234, 0.4);
}

.item-scroll {
  display: flex;
  gap: 0.75rem;
  min-width: min-content;
  padding: 0.5rem 0;
}

/* Fallback for browsers that don't support flex gap */
.item-card + .item-card {
  margin-left: 0.75rem;
}

.item-card {
  position: relative;
  background: var(--item-card-bg, rgba(255, 255, 255, 0.12));
  border-radius: 8px;
  padding: 0.75rem;
  min-width: 140px;
  max-width: 220px;
  width: 100%;
  text-align: center;
  flex-shrink: 0;
  transition: transform 0.18s ease;
  border: var(--item-card-border, 1px solid rgba(255, 255, 255, 0.08));
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  cursor: pointer;
  user-select: none; /* Prevent image selection */
}

.item-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--item-card-hover-shadow, 0 8px 20px rgba(0, 0, 0, 0.12));
}

@keyframes ready-glow {
  0% {
    box-shadow: 0 0 0 0 #667eea00;
    border-color: inherit;
  }
  100% {
    box-shadow: var(--item-card-ready-shadow, 0 0 0 3px #667eea88, 0 0 12px #667eea44);
    border-color: var(--item-card-ready-border, #667eea);
  }
}

:deep(.item-name) {
  font-size: 0.95rem;
  font-weight: 700;
  margin-bottom: 0.4rem;
  color: var(--item-name-color, #fff);
  line-height: 1.2;
  word-break: break-word;
}

/* Image styling */
:deep(.item-image) {
  width: 70px;
  height: 70px;
  object-fit: cover;
  border-radius: 6px;
  margin: 0 auto 0.4rem auto;
  display: block;
}

/* Mobile tweaks */
@media (max-width: 480px) {
  .item-card {
    min-width: 110px;
    max-width: 150px;
    padding: 0.6rem;
  }
  :deep(.item-name) {
    font-size: 0.86rem;
  }
  :deep(.item-image) {
    width: 50px;
    height: 50px;
    margin: 0 auto 0.3rem auto;
  }
  .scroll-wrapper::-webkit-scrollbar {
    height: 10px;
  }
  .scroll-wrapper::-webkit-scrollbar-thumb {
    border-width: 1px;
  }
}

.loading,
.error,
.empty {
  text-align: center;
  padding: 2rem 0;
  color: #888;
}
</style>
