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

const FALLBACK = 'https://files.skinbase.org/default/missing_md.webp'
const AVATAR_FALLBACK = 'https://files.skinbase.org/default/avatar_default.webp'

/* ── normalizers ─────────────────────────────────────────────────── */

function normalizeRelated(item) {
  if (!item?.url) return null
  return {
    id: item.id || item.slug || item.url,
    title: item.title || 'Untitled',
    author: item.author || 'Artist',
    authorAvatar: item.author_avatar || null,
    url: item.url,
    thumb: item.thumb || null,
    thumbSrcSet: item.thumb_srcset || null,
    maturity: item.maturity || null,
  }
}

function normalizeSimilar(item) {
  if (!item?.url) return null
  return {
    id: item.id || item.slug || item.url,
    title: item.title || 'Untitled',
    author: item.author || 'Artist',
    authorAvatar: item.author_avatar || null,
    url: item.url,
    thumb: item.thumb || null,
    thumbSrcSet: item.thumb_srcset || null,
    maturity: item.maturity || null,
  }
}

function normalizeRankItem(item) {
  const url = item?.urls?.direct || item?.urls?.web || item?.url || null
  if (!url) return null
  return {
    id: item.id || item.slug || url,
    title: item.title || 'Untitled',
    author: item?.author?.name || 'Artist',
    authorAvatar: item?.author?.avatar_url || null,
    url,
    thumb: item.thumbnail_url || item.thumb || null,
    thumbSrcSet: null,
    maturity: item.maturity || null,
  }
}

function dedupeByUrl(items) {
  const seen = new Set()
  return items.filter((item) => {
    if (item?.maturity?.should_hide) return false
    if (!item?.url || seen.has(item.url)) return false
    seen.add(item.url)
    return true
  })
}

/* ── Large art card (matches homepage style) ─────────────────── */

function RailCard({ item }) {
  const shouldBlur = Boolean(item?.maturity?.should_blur)
  const isMature = Boolean(item?.maturity?.is_mature_effective)

  return (
    <article className="w-[240px] shrink-0 snap-start sm:w-[220px] lg:w-[200px] xl:w-[210px] 2xl:w-[220px]">
      <a
        href={item.url}
        className="group relative block overflow-hidden rounded-2xl ring-1 ring-white/5 bg-black/20 shadow-lg shadow-black/40 transition-all duration-200 ease-out hover:-translate-y-0.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-300/70"
      >
        <div className="relative aspect-[4/3] overflow-hidden bg-neutral-900">
          {/* Gloss sheen */}
          <div className="absolute inset-0 bg-gradient-to-br from-white/10 via-white/5 to-transparent pointer-events-none z-10" />

          <img
            src={item.thumb || FALLBACK}
            srcSet={item.thumbSrcSet || undefined}
            sizes="220px"
            alt={item.title || 'Artwork'}
            className={`h-full w-full object-cover transition-[transform,filter] duration-300 ease-out group-hover:scale-[1.04] ${shouldBlur ? 'scale-[1.02] blur-xl' : ''}`}
            loading="lazy"
            decoding="async"
            onError={(e) => { e.currentTarget.src = FALLBACK }}
          />
          {isMature ? <div className="absolute left-3 top-3 z-20 rounded-full border border-amber-300/20 bg-black/60 px-3 py-1 text-[10px] font-semibold uppercase tracking-[0.16em] text-amber-100">Mature</div> : null}
          {shouldBlur ? <div className="absolute inset-x-3 bottom-3 z-20 rounded-full border border-amber-300/20 bg-black/60 px-3 py-1 text-[10px] font-semibold uppercase tracking-[0.16em] text-amber-100">Blurred by your settings</div> : null}

          {/* Bottom info overlay */}
          <div className="pointer-events-none absolute inset-x-0 bottom-0 z-20 bg-gradient-to-t from-black/80 via-black/40 to-transparent p-3 backdrop-blur-[2px] opacity-100 transition-opacity duration-200 md:opacity-0 md:group-hover:opacity-100 md:group-focus-visible:opacity-100">
            <div className="truncate text-sm font-semibold text-white">{item.title}</div>
            <div className="mt-1 flex items-center gap-2 text-xs text-white/80">
              <img
                src={item.authorAvatar || AVATAR_FALLBACK}
                alt={item.author}
                className="w-5 h-5 rounded-full object-cover shrink-0 ring-1 ring-white/20"
                onError={(e) => { e.currentTarget.src = AVATAR_FALLBACK }}
              />
              <span className="truncate">{item.author}</span>
            </div>
          </div>
        </div>
        <span className="sr-only">{item.title} by {item.author}</span>
      </a>
    </article>
  )
}

/* ── Scroll arrow button ─────────────────────────────────────── */

function ScrollBtn({ direction, onClick, visible }) {
  if (!visible) return null
  const isLeft = direction === 'left'
  return (
    <button
      onClick={onClick}
      aria-label={`Scroll ${direction}`}
      className={`absolute top-1/2 z-30 -translate-y-1/2 hidden lg:flex h-10 w-10 items-center justify-center rounded-full bg-black/60 text-white ring-1 ring-white/10 backdrop-blur-md transition hover:bg-black/80 ${isLeft ? 'left-2' : 'right-2'}`}
    >
      <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
        {isLeft
          ? <path strokeLinecap="round" strokeLinejoin="round" d="M15 19l-7-7 7-7" />
          : <path strokeLinecap="round" strokeLinejoin="round" d="M9 5l7 7-7 7" />}
      </svg>
    </button>
  )
}

/* ── Rail section (infinite loop + mouse-wheel scroll) ───────── */

function Rail({ title, emoji, items, seeAllHref }) {
  const scrollRef = useRef(null)
  const isResettingRef = useRef(false)
  const scrollEndTimer = useRef(null)
  const suppressClickTimerRef = useRef(null)
  const touchStartRef = useRef({ x: 0, y: 0 })
  const draggedRef = useRef(false)
  const suppressClickRef = useRef(false)
  const itemCount = items.length

  /* Triple items so we can loop seamlessly: [clone|original|clone] */
  const loopItems = useMemo(() => {
    if (!items.length) return []
    return [...items, ...items, ...items]
  }, [items])

  /* Pixel width of one item-set (measured from the DOM) */
  const getSetWidth = useCallback(() => {
    const el = scrollRef.current
    if (!el || el.children.length < itemCount + 1) return 0
    return el.children[itemCount].offsetLeft - el.children[0].offsetLeft
  }, [itemCount])

  /* Scroll step based on rendered card width + gap for predictable smooth motion */
  const getStepWidth = useCallback(() => {
    const el = scrollRef.current
    if (!el || el.children.length < 2) return el ? el.clientWidth * 0.75 : 0
    return el.children[1].offsetLeft - el.children[0].offsetLeft
  }, [])

  /* Centre on the middle (real) set after mount / data change */
  useEffect(() => {
    const el = scrollRef.current
    if (!el || !itemCount) return
    requestAnimationFrame(() => {
      const sw = getSetWidth()
      if (sw) {
        el.style.scrollBehavior = 'auto'
        el.scrollLeft = sw
        el.style.scrollBehavior = ''
      }
    })
  }, [loopItems, getSetWidth, itemCount])

  /* After scroll settles, silently jump back to the middle set if in a clone zone */
  const resetIfNeeded = useCallback(() => {
    if (isResettingRef.current) return
    const el = scrollRef.current
    if (!el || !itemCount) return
    const setW = getSetWidth()
    if (setW === 0) return

    if (el.scrollLeft < setW) {
      isResettingRef.current = true
      el.style.scrollBehavior = 'auto'
      el.scrollLeft += setW
      el.style.scrollBehavior = ''
      requestAnimationFrame(() => { isResettingRef.current = false })
    } else if (el.scrollLeft >= setW * 2) {
      isResettingRef.current = true
      el.style.scrollBehavior = 'auto'
      el.scrollLeft -= setW
      el.style.scrollBehavior = ''
      requestAnimationFrame(() => { isResettingRef.current = false })
    }
  }, [getSetWidth, itemCount])

  /* Keep user in the centre segment before scripted smooth scroll starts */
  const normalizeToMiddle = useCallback(() => {
    const el = scrollRef.current
    if (!el || !itemCount) return
    const setW = getSetWidth()
    if (setW === 0) return
    if (el.scrollLeft < setW || el.scrollLeft >= setW * 2) {
      el.style.scrollBehavior = 'auto'
      el.scrollLeft = ((el.scrollLeft % setW) + setW) % setW + setW
      el.style.scrollBehavior = ''
    }
  }, [getSetWidth, itemCount])

  /* Scroll listener: debounced boundary check + resize re-centre */
  useEffect(() => {
    const el = scrollRef.current
    if (!el) return
    const onScroll = () => {
      clearTimeout(scrollEndTimer.current)
      scrollEndTimer.current = setTimeout(resetIfNeeded, 80)
    }
    el.addEventListener('scroll', onScroll, { passive: true })

    const onResize = () => {
      const sw = getSetWidth()
      if (sw) {
        el.style.scrollBehavior = 'auto'
        el.scrollLeft = sw
        el.style.scrollBehavior = ''
      }
    }
    window.addEventListener('resize', onResize)
    return () => {
      el.removeEventListener('scroll', onScroll)
      window.removeEventListener('resize', onResize)
      clearTimeout(scrollEndTimer.current)
      clearTimeout(suppressClickTimerRef.current)
    }
  }, [loopItems, resetIfNeeded, getSetWidth])

  /* Mouse-wheel → horizontal scroll (re-attach when items arrive) */
  useEffect(() => {
    const el = scrollRef.current
    if (!el || !loopItems.length) return
    const onWheel = (e) => {
      if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
        e.preventDefault()
        el.scrollLeft += e.deltaY
      }
    }
    el.addEventListener('wheel', onWheel, { passive: false })
    return () => el.removeEventListener('wheel', onWheel)
  }, [loopItems])

  const scroll = useCallback((dir) => {
    const el = scrollRef.current
    if (!el) return
    normalizeToMiddle()
    const step = getStepWidth()
    const amount = step > 0 ? step * 2 : el.clientWidth * 0.75
    el.scrollBy({ left: dir === 'left' ? -amount : amount, behavior: 'smooth' })
    clearTimeout(scrollEndTimer.current)
    scrollEndTimer.current = setTimeout(resetIfNeeded, 260)
  }, [getStepWidth, normalizeToMiddle, resetIfNeeded])

  /* Prevent accidental link activation after horizontal swipe on touch devices */
  const onTouchStart = useCallback((e) => {
    if (!e.touches?.length) return
    const t = e.touches[0]
    touchStartRef.current = { x: t.clientX, y: t.clientY }
    draggedRef.current = false
  }, [])

  const onTouchMove = useCallback((e) => {
    if (!e.touches?.length) return
    const t = e.touches[0]
    const dx = Math.abs(t.clientX - touchStartRef.current.x)
    const dy = Math.abs(t.clientY - touchStartRef.current.y)
    if (dx > 10 && dx > dy) {
      draggedRef.current = true
    }
  }, [])

  const onTouchEnd = useCallback(() => {
    if (!draggedRef.current) return
    suppressClickRef.current = true
    clearTimeout(suppressClickTimerRef.current)
    suppressClickTimerRef.current = setTimeout(() => {
      suppressClickRef.current = false
    }, 260)
  }, [])

  const onClickCapture = useCallback((e) => {
    if (!suppressClickRef.current) return
    const link = e.target?.closest?.('a')
    if (link) {
      e.preventDefault()
      e.stopPropagation()
    }
  }, [])

  if (!items.length) return null

  return (
    <section>
      <div className="mb-5 flex items-center justify-between px-4 sm:px-6 lg:px-8">
        <h2 className="text-xl font-bold text-white">
          {emoji && <span className="mr-1.5">{emoji}</span>}{title}
        </h2>
        {seeAllHref && (
          <a href={seeAllHref} className="text-sm text-nova-300 hover:text-white transition">
            See all →
          </a>
        )}
      </div>

      <div className="relative" data-nav-swipe-ignore="1">
        {/* Permanent edge fades for infinite illusion */}
        <div className="pointer-events-none absolute inset-y-0 left-0 z-20 w-24 bg-gradient-to-r from-[#0F1724] to-transparent" />
        <div className="pointer-events-none absolute inset-y-0 right-0 z-20 w-24 bg-gradient-to-l from-[#0F1724] to-transparent" />

        <ScrollBtn direction="left" onClick={() => scroll('left')} visible={true} />
        <ScrollBtn direction="right" onClick={() => scroll('right')} visible={true} />

        <div
          ref={scrollRef}
          onTouchStart={onTouchStart}
          onTouchMove={onTouchMove}
          onTouchEnd={onTouchEnd}
          onClickCapture={onClickCapture}
          className="flex gap-4 overflow-x-auto px-4 pb-3 sm:px-6 lg:px-8 snap-x snap-mandatory scroll-smooth scrollbar-hide [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
        >
          {loopItems.map((item, idx) => (
            <RailCard key={`${item.id || item.url}-${idx}`} item={item} />
          ))}
        </div>
      </div>
    </section>
  )
}

/* ── Main export ─────────────────────────────────────────────── */

export default function ArtworkRecommendationsRails({ artwork, related = [] }) {
  const [similarApiItems, setSimilarApiItems] = useState([])
  const [similarLoaded, setSimilarLoaded] = useState(false)
  const [trendingItems, setTrendingItems] = useState([])

  const relatedCards = useMemo(() => {
    return dedupeByUrl((Array.isArray(related) ? related : []).map(normalizeRelated).filter(Boolean))
  }, [related])

  useEffect(() => {
    let isCancelled = false

    const loadSimilar = async () => {
      if (!artwork?.id) {
        setSimilarApiItems([])
        setSimilarLoaded(true)
        return
      }

      try {
        const response = await fetch(`/api/art/${artwork.id}/similar-ai`, { credentials: 'same-origin' })
        if (!response.ok) throw new Error('similar fetch failed')
        const payload = await response.json()
        const items = dedupeByUrl((payload?.data || []).map(normalizeSimilar).filter(Boolean))
        if (!isCancelled) {
          setSimilarApiItems(items)
          setSimilarLoaded(true)
        }
      } catch {
        if (!isCancelled) {
          setSimilarApiItems([])
          setSimilarLoaded(true)
        }
      }
    }

    loadSimilar()
    return () => {
      isCancelled = true
    }
  }, [artwork?.id])

  useEffect(() => {
    let isCancelled = false

    const loadTrending = async () => {
      const categoryId = artwork?.categories?.[0]?.id
      if (!categoryId) {
        setTrendingItems([])
        return
      }

      try {
        const response = await fetch(`/api/rank/category/${categoryId}?type=trending`, { credentials: 'same-origin' })
        if (!response.ok) throw new Error('trending fetch failed')
        const payload = await response.json()
        const items = dedupeByUrl((payload?.data || []).map(normalizeRankItem).filter(Boolean))
        if (!isCancelled) setTrendingItems(items)
      } catch {
        if (!isCancelled) setTrendingItems([])
      }
    }

    loadTrending()
    return () => {
      isCancelled = true
    }
  }, [artwork?.categories])

  const authorName = String(artwork?.user?.name || artwork?.user?.username || '').trim().toLowerCase()

  const tagBasedFallback = useMemo(() => {
    return relatedCards.filter((item) => String(item.author || '').trim().toLowerCase() !== authorName)
  }, [relatedCards, authorName])

  const similarItems = useMemo(() => {
    if (!similarLoaded) return []
    if (similarApiItems.length > 0) return similarApiItems.slice(0, 12)
    if (tagBasedFallback.length > 0) return tagBasedFallback.slice(0, 12)
    return trendingItems.slice(0, 12)
  }, [similarLoaded, similarApiItems, tagBasedFallback, trendingItems])

  const trendingRailItems = useMemo(() => trendingItems.slice(0, 12), [trendingItems])

  if (similarItems.length === 0 && trendingRailItems.length === 0) return null

  const categoryName = artwork?.categories?.[0]?.name
  const trendingLabel = categoryName
    ? `Trending in ${categoryName}`
    : 'Trending'

  const trendingHref = categoryName
    ? `/discover/trending`
    : '/discover/trending'

  const similarHref = artwork?.id ? `/art/${artwork.id}/similar` : null

  return (
    <div className="space-y-14">
      <Rail title="Similar Artworks" emoji="✨" items={similarItems} seeAllHref={similarHref} />
      <Rail title={trendingLabel} emoji="🔥" items={trendingRailItems} seeAllHref={trendingHref} />
    </div>
  )
}
