import React, { startTransition, useDeferredValue, useEffect, useRef, useState } from 'react'
import { createRoot } from 'react-dom/client'
import CategoryCard from '../components/category/CategoryCard'
import Pagination from '../components/forum/Pagination'

const SORT_OPTIONS = [
  { value: 'popular', label: 'Popular' },
  { value: 'az', label: 'A-Z' },
  { value: 'artworks', label: 'Most artworks' },
]

const PAGE_SIZE = 24

const numberFormatter = new Intl.NumberFormat()

function LoadingGrid() {
  return (
    <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
      {Array.from({ length: 8 }).map((_, index) => (
        <div key={index} className="aspect-[4/5] animate-pulse rounded-2xl border border-white/8 bg-white/[0.04]" />
      ))}
    </div>
  )
}

function EmptyState({ query }) {
  return (
    <div className="rounded-[28px] border border-dashed border-white/14 bg-black/20 px-6 py-14 text-center backdrop-blur-sm">
      <p className="text-xs font-semibold uppercase tracking-[0.24em] text-white/35">No matching categories</p>
      <h2 className="mt-3 text-2xl font-semibold tracking-[-0.03em] text-white">Nothing matched "{query}"</h2>
      <p className="mx-auto mt-3 max-w-xl text-sm leading-7 text-white/58">
        Try a shorter term or switch sorting to browse the full category directory again.
      </p>
    </div>
  )
}

function ErrorState({ onRetry }) {
  return (
    <div className="rounded-[28px] border border-rose-400/20 bg-rose-500/8 px-6 py-14 text-center shadow-[0_30px_70px_rgba(0,0,0,0.2)]">
      <p className="text-xs font-semibold uppercase tracking-[0.24em] text-rose-200/70">Unable to load categories</p>
      <h2 className="mt-3 text-2xl font-semibold tracking-[-0.03em] text-white">The directory API did not respond cleanly.</h2>
      <p className="mx-auto mt-3 max-w-xl text-sm leading-7 text-white/58">
        Refresh the list and try again. If this persists, the API route or cache payload needs inspection.
      </p>
      <button
        type="button"
        onClick={onRetry}
        className="mt-6 inline-flex items-center justify-center rounded-full border border-rose-300/35 bg-rose-400/12 px-5 py-3 text-sm font-semibold text-rose-100 transition hover:border-rose-200/55 hover:bg-rose-400/20"
      >
        Retry request
      </button>
    </div>
  )
}

function getInitialPage() {
  if (typeof window === 'undefined') {
    return 1
  }

  const rawPage = Number(new URL(window.location.href).searchParams.get('page') || 1)

  if (!Number.isFinite(rawPage) || rawPage < 1) {
    return 1
  }

  return Math.floor(rawPage)
}

function getInitialSort() {
  if (typeof window === 'undefined') {
    return 'popular'
  }

  const sort = new URL(window.location.href).searchParams.get('sort') || 'popular'
  return SORT_OPTIONS.some((option) => option.value === sort) ? sort : 'popular'
}

function getInitialSearchQuery() {
  if (typeof window === 'undefined') {
    return ''
  }

  return new URL(window.location.href).searchParams.get('q') || ''
}

function syncQueryState({ page, sort, query }) {
  if (typeof window === 'undefined') {
    return
  }

  const url = new URL(window.location.href)

  if (page <= 1) {
    url.searchParams.delete('page')
  } else {
    url.searchParams.set('page', String(page))
  }

  if (sort === 'popular') {
    url.searchParams.delete('sort')
  } else {
    url.searchParams.set('sort', sort)
  }

  if (query.trim() === '') {
    url.searchParams.delete('q')
  } else {
    url.searchParams.set('q', query)
  }

  window.history.replaceState({}, '', url.toString())
}

function CategoriesPage({ apiUrl = '/api/categories', pageTitle = 'Categories', pageDescription = '' }) {
  const [categories, setCategories] = useState([])
  const [popularCategories, setPopularCategories] = useState([])
  const [meta, setMeta] = useState({ current_page: 1, last_page: 1, per_page: PAGE_SIZE, total: 0 })
  const [summary, setSummary] = useState({ total_categories: 0, total_artworks: 0 })
  const [loading, setLoading] = useState(true)
  const [loadingMore, setLoadingMore] = useState(false)
  const [error, setError] = useState(false)
  const [searchQuery, setSearchQuery] = useState(() => getInitialSearchQuery())
  const [sort, setSort] = useState(() => getInitialSort())
  const [currentPage, setCurrentPage] = useState(() => getInitialPage())
  const deferredQuery = useDeferredValue(searchQuery)
  const sentinelRef = useRef(null)

  const loadCategories = async ({ signal, page, query, activeSort, append = false }) => {
    if (append) {
      setLoadingMore(true)
    } else {
      setLoading(true)
    }

    setError(false)

    try {
      const params = new URLSearchParams({
        page: String(page),
        per_page: String(PAGE_SIZE),
        sort: activeSort,
      })

      if (query.trim() !== '') {
        params.set('q', query.trim())
      }

      const response = await fetch(`${apiUrl}?${params.toString()}`, {
        headers: {
          Accept: 'application/json',
          'X-Requested-With': 'XMLHttpRequest',
        },
        credentials: 'same-origin',
        signal,
      })

      if (!response.ok) {
        throw new Error('Failed to load categories')
      }

      const payload = await response.json()
      const nextCategories = Array.isArray(payload?.data) ? payload.data : []

      setCategories((previous) => {
        if (!append) {
          return nextCategories
        }

        const seenIds = new Set(previous.map((category) => category.id))
        const merged = [...previous]

        nextCategories.forEach((category) => {
          if (!seenIds.has(category.id)) {
            merged.push(category)
          }
        })

        return merged
      })
      setPopularCategories(Array.isArray(payload?.popular_categories) ? payload.popular_categories : [])
      setMeta(payload?.meta || { current_page: 1, last_page: 1, per_page: PAGE_SIZE, total: 0 })
      setSummary(payload?.summary || { total_categories: 0, total_artworks: 0 })

      if ((payload?.meta?.current_page ?? page) !== currentPage) {
        setCurrentPage(payload?.meta?.current_page ?? page)
      }
    } catch (requestError) {
      if (requestError?.name !== 'AbortError') {
        setError(true)
      }
    } finally {
      if (!signal?.aborted || signal === undefined) {
        setLoading(false)
        setLoadingMore(false)
      }
    }
  }

  useEffect(() => {
    const controller = new AbortController()

    void loadCategories({
      signal: controller.signal,
      page: currentPage,
      query: deferredQuery,
      activeSort: sort,
      append: false,
    })

    return () => controller.abort()
  }, [apiUrl, deferredQuery, sort])

  useEffect(() => {
    syncQueryState({ page: currentPage, sort, query: deferredQuery })
  }, [currentPage, deferredQuery, sort])

  const handlePageChange = (page) => {
    setCategories([])
    setCurrentPage(page)

    void loadCategories({
      page,
      query: deferredQuery,
      activeSort: sort,
      append: false,
    })

    if (typeof window !== 'undefined') {
      window.scrollTo({ top: 0, behavior: 'smooth' })
    }
  }

  useEffect(() => {
    const sentinel = sentinelRef.current
    const hasMore = meta.current_page < meta.last_page

    if (!sentinel || loading || loadingMore || error || !hasMore) {
      return undefined
    }

    const observer = new IntersectionObserver((entries) => {
      const firstEntry = entries[0]

      if (!firstEntry?.isIntersecting) {
        return
      }

      const nextPage = meta.current_page + 1
      setCurrentPage(nextPage)
      void loadCategories({
        page: nextPage,
        query: deferredQuery,
        activeSort: sort,
        append: true,
      })
    }, { rootMargin: '320px 0px' })

    observer.observe(sentinel)

    return () => observer.disconnect()
  }, [deferredQuery, error, loading, loadingMore, meta.current_page, meta.last_page, sort])

  const handleRetry = () => {
    void loadCategories({
      page: currentPage,
      query: deferredQuery,
      activeSort: sort,
      append: false,
    })
  }

  const loadedCount = categories.length
  const showingStart = loadedCount > 0 ? 1 : 0
  const showingEnd = loadedCount
  const hasMorePages = meta.current_page < meta.last_page

  return (
    <div className="pb-24 text-white">
      <section className="relative overflow-hidden">
        <div className="absolute inset-x-0 top-0 h-[28rem] bg-[radial-gradient(circle_at_top_left,rgba(34,211,238,0.12),transparent_38%),radial-gradient(circle_at_top_right,rgba(249,115,22,0.14),transparent_34%)]" />
        <div className="relative w-full px-6 pb-8 pt-14 sm:px-8 sm:pt-20 xl:px-10 2xl:px-14 lg:pt-24">
          <div className="grid gap-8 lg:grid-cols-[minmax(0,1.2fr)_20rem] lg:items-end">
            <div>
              <div className="inline-flex rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-xs font-semibold uppercase tracking-[0.24em] text-white/50 backdrop-blur-sm">
                Category directory
              </div>
              <h1 className="mt-5 max-w-4xl text-4xl font-semibold tracking-[-0.05em] text-white sm:text-5xl lg:text-6xl">
                {pageTitle}
              </h1>
              <p className="mt-5 max-w-2xl text-base leading-8 text-white/62 sm:text-lg">
                {pageDescription || 'Browse all wallpapers, skins, themes and digital art categories'}
              </p>
            </div>

            <div className="grid gap-4 sm:grid-cols-3 lg:grid-cols-1">
              <div className="rounded-[24px] border border-white/10 bg-black/22 p-5 backdrop-blur-md shadow-[0_24px_60px_rgba(0,0,0,0.24)]">
                <p className="text-xs font-semibold uppercase tracking-[0.2em] text-white/40">Categories</p>
                <p className="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">{numberFormatter.format(summary.total_categories)}</p>
              </div>
              <div className="rounded-[24px] border border-white/10 bg-black/22 p-5 backdrop-blur-md shadow-[0_24px_60px_rgba(0,0,0,0.24)]">
                <p className="text-xs font-semibold uppercase tracking-[0.2em] text-white/40">Artworks indexed</p>
                <p className="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">{numberFormatter.format(summary.total_artworks)}</p>
              </div>
              <div className="rounded-[24px] border border-white/10 bg-black/22 p-5 backdrop-blur-md shadow-[0_24px_60px_rgba(0,0,0,0.24)]">
                <p className="text-xs font-semibold uppercase tracking-[0.2em] text-white/40">View</p>
                <p className="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">Grid</p>
              </div>
            </div>
          </div>

          <div className="mt-10 rounded-[30px] border border-white/10 bg-black/25 p-4 shadow-[0_30px_80px_rgba(0,0,0,0.25)] backdrop-blur-xl sm:p-5">
            <div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_16rem] lg:items-center">
              <label className="relative block">
                <span className="pointer-events-none absolute left-4 top-1/2 -translate-y-1/2 text-white/35">
                  <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" className="h-5 w-5">
                    <path fillRule="evenodd" d="M8.5 3a5.5 5.5 0 1 0 3.473 9.765l3.63 3.63a.75.75 0 1 0 1.06-1.06l-3.63-3.63A5.5 5.5 0 0 0 8.5 3Zm-4 5.5a4 4 0 1 1 8 0 4 4 0 0 1-8 0Z" clipRule="evenodd" />
                  </svg>
                </span>
                <input
                  type="search"
                  value={searchQuery}
                  onChange={(event) => {
                    const value = event.target.value
                    startTransition(() => {
                      setSearchQuery(value)
                      setCurrentPage(1)
                    })
                  }}
                  placeholder="Search categories"
                  aria-label="Search categories"
                  className="h-14 w-full rounded-2xl border border-white/10 bg-white/[0.04] pl-12 pr-4 text-sm text-white placeholder:text-white/28 focus:border-cyan-300/45 focus:outline-none focus:ring-2 focus:ring-cyan-300/15"
                />
              </label>

              <label className="block">
                <span className="mb-2 block text-xs font-semibold uppercase tracking-[0.2em] text-white/38">Sort by</span>
                <select
                  value={sort}
                  onChange={(event) => {
                    setSort(event.target.value)
                    setCurrentPage(1)
                  }}
                  aria-label="Sort categories"
                  className="h-14 w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 text-sm text-white focus:border-orange-300/45 focus:outline-none focus:ring-2 focus:ring-orange-300/12"
                >
                  {SORT_OPTIONS.map((option) => (
                    <option key={option.value} value={option.value} className="bg-slate-950 text-white">
                      {option.label}
                    </option>
                  ))}
                </select>
              </label>
            </div>
          </div>
        </div>
      </section>

      <section className="w-full px-6 sm:px-8 xl:px-10 2xl:px-14">
        {!loading && !error && deferredQuery.trim() === '' && popularCategories.length > 0 && (
          <div className="mb-10 rounded-[28px] border border-white/10 bg-white/[0.03] p-5 shadow-[0_24px_60px_rgba(0,0,0,0.18)] backdrop-blur-sm">
            <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
              <div>
                <p className="text-xs font-semibold uppercase tracking-[0.22em] text-white/38">Popular categories</p>
                <h2 className="mt-2 text-2xl font-semibold tracking-[-0.04em] text-white">Start with the busiest destinations</h2>
              </div>
              <div className="flex flex-wrap gap-3">
                {popularCategories.map((category) => (
                  <a
                    key={category.id}
                    href={category.url}
                    className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-black/20 px-4 py-2 text-sm text-white/72 transition hover:border-white/20 hover:bg-white/[0.05] hover:text-white"
                  >
                    <span>{category.name}</span>
                    <span className="text-white/38">{numberFormatter.format(category.artwork_count)}</span>
                  </a>
                ))}
              </div>
            </div>
          </div>
        )}

        <div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
          <div>
            <p className="text-xs font-semibold uppercase tracking-[0.22em] text-white/38">Directory results</p>
            <h2 className="mt-2 text-2xl font-semibold tracking-[-0.04em] text-white">
              {numberFormatter.format(meta.total)} categories visible
            </h2>
          </div>
          {!loading && !error && meta.total > 0 ? (
            <p className="text-sm text-white/52">
              Showing {numberFormatter.format(showingStart)} to {numberFormatter.format(showingEnd)} of {numberFormatter.format(meta.total)} categories.
            </p>
          ) : (
            <p className="text-sm text-white/52">
              Browse all wallpapers, skins, themes and digital art categories.
            </p>
          )}
        </div>

        {loading && <LoadingGrid />}
        {!loading && error && <ErrorState onRetry={handleRetry} />}
        {!loading && !error && meta.total === 0 && <EmptyState query={deferredQuery} />}

        {!loading && !error && meta.total > 0 && (
          <>
            <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
              {categories.map((category, index) => (
                <CategoryCard key={category.id} category={category} index={index} />
              ))}
            </div>

            <div ref={sentinelRef} className="h-6 w-full" aria-hidden="true" />

            {loadingMore && (
              <div className="mt-6 flex items-center justify-center gap-3 rounded-2xl border border-white/8 bg-black/18 px-4 py-4 text-sm text-white/56 backdrop-blur-sm">
                <span className="h-2.5 w-2.5 animate-pulse rounded-full bg-cyan-300" />
                Loading more categories
              </div>
            )}

            <div className="mt-10 flex flex-col items-center justify-center gap-3 rounded-[24px] border border-white/8 bg-black/18 px-4 py-5 backdrop-blur-sm">
              <p className="text-sm text-white/46">
                Loaded through page {numberFormatter.format(meta.current_page)} of {numberFormatter.format(meta.last_page)}
              </p>
              <Pagination meta={meta} onPageChange={handlePageChange} />
              {hasMorePages && (
                <p className="text-xs uppercase tracking-[0.2em] text-white/28">
                  Scroll to load the next page automatically
                </p>
              )}
            </div>
          </>
        )}
      </section>
    </div>
  )
}

const mountElement = document.getElementById('categories-page-root')

if (mountElement) {
  let props = {}

  try {
    const propsElement = document.getElementById('categories-page-props')
    props = propsElement ? JSON.parse(propsElement.textContent || '{}') : {}
  } catch {
    props = {}
  }

  createRoot(mountElement).render(<CategoriesPage {...props} />)
}

export default CategoriesPage
