<template>
  <Teleport to="body">
    <div v-if="modelValue" class="modal d-block" tabindex="-1" style="z-index:1055;padding-top:72px;padding-bottom:80px">
      <div class="modal-dialog modal-lg modal-dialog-scrollable">
        <div class="modal-content" style="background:var(--bg-card);color:var(--text-primary)">
          <div class="modal-header border-0 pb-0">
            <div class="d-flex align-items-center gap-2 w-100 me-2">
              <i class="fas fa-images" style="color:var(--accent-color)"></i>
              <input v-model="query" type="text" class="form-control rounded-pill form-control-sm"
                placeholder="Search photos…" style="background:var(--bg-primary);color:var(--text-primary);border-color:rgba(128,128,128,.3)" />
            </div>
            <button type="button" class="btn-close" @click="$emit('update:modelValue', false)" />
          </div>
          <div class="modal-body pt-2">
            <div v-if="error" class="alert alert-danger alert-dismissible py-2 mb-2">
              {{ error }} <button type="button" class="btn-close" @click="error=null"/>
            </div>
            <!-- skeleton -->
            <div v-if="loading && !photos.length" class="row g-2">
              <div v-for="n in 9" :key="n" class="col-4">
                <div class="ratio ratio-4x3 rounded" style="background:rgba(128,128,128,.15);animation:pulse 1.5s infinite" />
              </div>
            </div>
            <!-- grid -->
            <div v-else class="row g-2">
              <div v-for="photo in photos" :key="photo.id" class="col-4" style="cursor:pointer" @click="selectPhoto(photo)">
                <div class="ratio ratio-4x3 position-relative rounded overflow-hidden">
                  <img :src="photo.thumb" class="w-100 h-100 object-fit-cover" :alt="photo.title" loading="lazy" />
                  <div v-if="selecting===photo.id" class="position-absolute top-0 start-0 w-100 h-100 d-flex align-items-center justify-content-center" style="background:rgba(0,0,0,.45)">
                    <div class="spinner-border text-light spinner-border-sm" />
                  </div>
                </div>
                <small class="text-muted d-block text-truncate mt-1 px-1" style="font-size:.7rem">{{ photo.title }}</small>
              </div>
            </div>
            <!-- empty states -->
            <div v-if="!loading && !photos.length && !error && !query.trim()" class="text-center text-muted py-4">
              <i class="fas fa-search d-block mb-2" style="font-size:1.5rem;opacity:.5"></i>
              Type a product name above to search photos.
            </div>
            <div v-else-if="!loading && !photos.length && !error && query.trim()" class="text-center text-muted py-4">
              <i class="fas fa-image d-block mb-2" style="font-size:1.5rem;opacity:.5"></i>
              No photos found for “{{ query.trim() }}”.
            </div>
            <!-- sentinel for infinite scroll -->
            <div ref="sentinel" class="py-2 text-center">
              <div v-if="loadingMore" class="spinner-border spinner-border-sm text-muted" />
            </div>
          </div>
        </div>
      </div>
      <div class="modal-backdrop show" style="z-index:-1" @click="$emit('update:modelValue', false)" />
    </div>
  </Teleport>
</template>

<script setup>
import { ref, watch, nextTick } from 'vue'
import axios from 'axios'

const props = defineProps({ modelValue: Boolean, productName: { type: String, default: '' } })
const emit = defineEmits(['update:modelValue', 'photo-selected'])

const photos    = ref([])
const query     = ref('')
const page      = ref(1)
const hasMore   = ref(false)
const loading   = ref(false)
const loadingMore = ref(false)
const selecting = ref(null)
const error     = ref(null)
const sentinel  = ref(null)
let observer = null
let debounceTimer = null

watch(() => props.modelValue, async (val) => {
  if (val) { query.value = props.productName; await resetAndSearch() }
  else { photos.value = []; page.value = 1; observer?.disconnect() }
})

watch(query, () => {
  clearTimeout(debounceTimer)
  debounceTimer = setTimeout(() => resetAndSearch(), 400)
})

async function resetAndSearch() {
  observer?.disconnect()
  photos.value = []; page.value = 1; error.value = null
  // Don't fire a request with an empty query — the API rejects it (422).
  if (!query.value.trim()) { loading.value = false; return }
  loading.value = true
  await fetchPage(1)
  loading.value = false
  await nextTick()
  setupObserver()
}

async function fetchPage(p) {
  try {
    const res = await axios.get('/api/products/photo-search', { params: { q: query.value.trim(), page: p } })
    if (res.data.success) {
      photos.value.push(...res.data.photos)
      hasMore.value = res.data.has_more
      page.value = p
    } else {
      error.value = res.data.error || 'Could not load photos. Try again.'
    }
  } catch (e) {
    error.value = e?.response?.data?.error || 'Could not load photos. Try again.'
  }
}

async function loadMore() {
  if (!hasMore.value || loadingMore.value) return
  loadingMore.value = true
  await fetchPage(page.value + 1)
  loadingMore.value = false
  await nextTick()
  setupObserver()
}

function setupObserver() {
  observer?.disconnect()
  if (!sentinel.value) return
  observer = new IntersectionObserver(([e]) => { if (e.isIntersecting) loadMore() }, { threshold: 0.1 })
  observer.observe(sentinel.value)
}

async function selectPhoto(photo) {
  if (selecting.value) return
  selecting.value = photo.id
  error.value = null
  try {
    const res = await axios.post('/api/products/photo-download', { src: photo.src })
    if (res.data.success) {
      emit('photo-selected', { hashkey: res.data.hashkey, url: res.data.url })
      emit('update:modelValue', false)
    } else {
      error.value = 'Failed to save photo. Try another.'
    }
  } catch {
    error.value = 'Failed to save photo. Try another.'
  } finally {
    selecting.value = null
  }
}
</script>

<style scoped>
@keyframes pulse { 0%,100%{opacity:.6} 50%{opacity:.3} }
</style>
