import { useCallback, useEffect, useRef, useState } from 'react'

const VISION_POLL_INTERVAL_MS = 5000
const VISION_DEBOUNCE_MS = 3000

const initialDebug = {
  enabled: null,
  queueConnection: '',
  queuedJobs: 0,
  failedJobs: 0,
  triggered: false,
  aiTagCount: 0,
  totalTagCount: 0,
  syncDone: false,
  lastError: '',
}

/**
 * useVisionTags
 *
 * Two-phase Vision AI tag suggestions triggered as soon as the upload is ready,
 * BEFORE the user navigates to the Details step so suggestions arrive early:
 *
 * Phase 1 — Immediate (on upload completion):
 *   POST /api/uploads/{id}/vision-suggest
 *   Calls the Vision gateway (/analyze/all) synchronously and returns
 *   CLIP + YOLO tag suggestions within ~5-8 s. Results are shown right away.
 *
 * Phase 2 — Background polling:
 *   GET /api/artworks/{id}/tags?trigger=1
 *   Triggers the queue-based AutoTagArtworkJob, then polls every 5 s until
 *   the DB-persisted AI tags appear (after job completes). Merges with Phase 1
 *   results so the suggestions panel stays populated regardless of queue lag.
 *
 * @param {number|null} artworkId
 * @param {boolean}     uploadReady  true once the upload reaches ready_to_publish
 * @returns {{ visionSuggestedTags: any[], visionDebug: object }}
 */
export default function useVisionTags(artworkId, uploadReady) {
  const [visionSuggestedTags, setVisionSuggestedTags] = useState([])
  const [visionDebug, setVisionDebug] = useState(initialDebug)

  // Refs for deduplication
  const syncDoneRef = useRef(false)
  const lastPollAtRef = useRef(0)
  const abortRef = useRef(null)

  // ── Tag merging helper ──────────────────────────────────────────────────
  const mergeTags = useCallback((incoming) => {
    setVisionSuggestedTags((prev) => {
      if (!incoming.length) return prev
      const seen = new Set(prev.map((t) => t?.slug || t?.name || t))
      const next = [...prev]
      for (const tag of incoming) {
        const key = tag?.slug || tag?.name || tag
        if (!seen.has(key)) {
          seen.add(key)
          next.push(tag)
        }
      }
      return next
    })
  }, [])

  // ── Phase 1: Immediate gateway call ────────────────────────────────────
  const callGatewaySync = useCallback(async () => {
    if (!artworkId || artworkId <= 0 || syncDoneRef.current) return
    syncDoneRef.current = true

    if (abortRef.current) abortRef.current.abort()
    abortRef.current = new AbortController()

    try {
      const response = await window.axios.post(
        `/api/uploads/${artworkId}/vision-suggest`,
        {},
        { signal: abortRef.current.signal },
      )
      const payload = response?.data || {}

      if (payload?.vision_enabled === false) {
        setVisionDebug((prev) => ({ ...prev, enabled: false, syncDone: true }))
        return
      }

      const tags = Array.isArray(payload?.tags) ? payload.tags : []
      mergeTags(tags)

      setVisionDebug((prev) => ({
        ...prev,
        enabled: true,
        syncDone: true,
        aiTagCount: Math.max(prev.aiTagCount, tags.length),
      }))

      window.console?.debug?.('[upload][vision-tags][sync]', {
        artworkId,
        count: tags.length,
        source: payload?.source,
      })
    } catch (err) {
      if (err?.code === 'ERR_CANCELED') return
      setVisionDebug((prev) => ({
        ...prev,
        syncDone: true,
        lastError: err?.response?.data?.reason || err?.message || '',
      }))
    }
  }, [artworkId, mergeTags])

  // ── Phase 2: Background DB poll ─────────────────────────────────────────
  const pollDbTags = useCallback(async () => {
    if (!artworkId || artworkId <= 0) return

    const now = Date.now()
    if (now - lastPollAtRef.current < VISION_DEBOUNCE_MS) return
    lastPollAtRef.current = now

    try {
      const response = await window.axios.get(`/api/artworks/${artworkId}/tags`, {
        params: { trigger: 1 },
      })
      const payload = response?.data || {}

      if (payload?.vision_enabled === false) {
        setVisionDebug((prev) => ({ ...prev, enabled: false }))
        return
      }

      const aiTags = Array.isArray(payload?.ai_tags) ? payload.ai_tags : []
      mergeTags(aiTags)

      const debug = payload?.debug || {}
      setVisionDebug((prev) => ({
        ...prev,
        enabled: Boolean(payload?.vision_enabled),
        queueConnection: String(debug?.queue_connection || prev.queueConnection),
        queuedJobs: Number(debug?.queued_jobs ?? prev.queuedJobs),
        failedJobs: Number(debug?.failed_jobs ?? prev.failedJobs),
        triggered: Boolean(debug?.triggered),
        aiTagCount: Math.max(prev.aiTagCount, Number(debug?.ai_tag_count || aiTags.length || 0)),
        totalTagCount: Number(debug?.total_tag_count || 0),
        lastError: '',
      }))

      window.console?.debug?.('[upload][vision-tags][poll]', {
        artworkId,
        aiTags: aiTags.map((t) => t?.slug || t?.name || t),
      })
    } catch (err) {
      if (err?.response?.status === 404 || err?.response?.status === 403) return
      setVisionDebug((prev) => ({
        ...prev,
        lastError: err?.response?.data?.message || err?.message || '',
      }))
    }
  }, [artworkId, mergeTags])

  // ── Lifecycle ────────────────────────────────────────────────────────────
  useEffect(() => {
    if (!artworkId || !uploadReady) return

    // Kick off the immediate gateway call
    callGatewaySync()

    // Start background polling
    pollDbTags()
    const timer = window.setInterval(pollDbTags, VISION_POLL_INTERVAL_MS)

    return () => {
      window.clearInterval(timer)
      abortRef.current?.abort()
    }
  }, [artworkId, uploadReady, callGatewaySync, pollDbTags])

  // Reset when artworkId changes (new upload)
  useEffect(() => {
    syncDoneRef.current = false
    lastPollAtRef.current = 0
    setVisionSuggestedTags([])
    setVisionDebug(initialDebug)
  }, [artworkId])

  return { visionSuggestedTags, visionDebug }
}
