---
import { icon, library } from '@fortawesome/fontawesome-svg-core'
import { faSort, faSortDown, faSortUp } from '@fortawesome/free-solid-svg-icons'
import Xmark from '~/icons/XmarkIcon.astro'
import { type ZenTheme } from '~/mods'
import { getPath, type Locale } from '~/utils/i18n'

// Add icons to the library
library.add(faSort, faSortUp, faSortDown)

// Create icon objects
const defaultSortIcon = icon({ prefix: 'fas', iconName: 'sort' })
const ascSortIcon = icon({ prefix: 'fas', iconName: 'sort-up' })
const descSortIcon = icon({ prefix: 'fas', iconName: 'sort-down' })

interface Props {
  allMods: ZenTheme[]
  locale: Locale
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  translations: any
}

const { allMods, locale, translations } = Astro.props

const getLocalePath = getPath(locale)

// Server-side rendering setup
const defaultLimit = 12
const initialMods = allMods.slice(0, defaultLimit)
const totalPages = Math.ceil(allMods.length / defaultLimit)
---

<div id="mods-list-container" class="flex flex-1 flex-col">
  <div class="flex flex-col items-center gap-4">
    <div
      class="flex w-full flex-row items-center justify-center rounded-full border-2 border-dark pr-6"
    >
      <input
        class="w-full rounded-full bg-transparent py-2 pl-6 pr-4 text-lg outline-none"
        id="search"
        placeholder={translations.search}
        type="text"
      />
      <button
        id="clear-search"
        title="Clear search"
        class="hidden rounded-full p-1 transition-colors duration-150 hover:bg-subtle"
        aria-label="Clear search"
        tabindex="0"
      >
        <Xmark />
      </button>
    </div>

    <div class="mb-1 flex w-full items-center justify-between gap-4 sm:mb-2">
      <div class="flex items-start gap-4">
        <button
          class="flex items-center gap-2 rounded-full border border-subtle px-5 py-1 text-sm font-semibold shadow-sm transition-colors hover:bg-muted focus:bg-coral/10 sm:text-base"
          id="created-sort"
          type="button"
        >
          {translations.sort.lastCreated}
          <span class="relative">
            <span id="created-sort-default" class="" set:html={defaultSortIcon.html[0]} />
            <span id="created-sort-asc" class="hidden" set:html={ascSortIcon.html[0]} />
            <span id="created-sort-desc" class="hidden" set:html={descSortIcon.html[0]} />
          </span>
        </button>
        <button
          class="flex items-center gap-2 rounded-full border border-subtle px-5 py-1 text-sm font-semibold shadow-sm transition-colors hover:bg-muted focus:bg-coral/10 sm:text-base"
          id="updated-sort"
          type="button"
        >
          {translations.sort.lastUpdated}
          <span class="relative">
            <span id="updated-sort-default" class="" set:html={defaultSortIcon.html[0]} />
            <span id="updated-sort-asc" class="hidden" set:html={ascSortIcon.html[0]} />
            <span id="updated-sort-desc" class="hidden" set:html={descSortIcon.html[0]} />
          </span>
        </button>
      </div>

      <div class="hidden items-center gap-2 px-4 py-1 sm:flex">
        <label class="text-md font-semibold" for="limit">
          {translations.sort.perPage}
        </label>
        <select class="rounded border border-dark bg-paper px-2 py-1 text-sm" id="limit">
          <option value="12">12</option>
          <option value="24">24</option>
          <option value="48">48</option>
          <option value="96">96</option>
        </select>
      </div>
    </div>
  </div>
  <div
    id="mods-grid"
    class="grid w-full grid-cols-1 place-items-start gap-12 py-6 md:grid-cols-2 xl:grid-cols-3"
  >
    {
      initialMods.map(mod => (
        <a
          class="mod-card flex w-full flex-col gap-4 border-transparent transition-colors duration-100 hover:opacity-90"
          href={getLocalePath(`/mods/${mod.id}`)}
        >
          <div class="relative mb-0 block aspect-[1.85/1] h-48 overflow-hidden rounded-md border-2 border-dark object-cover shadow-md">
            <img
              alt={mod.name}
              class="h-full w-full object-cover transition-transform duration-100 hover:scale-105"
              loading="lazy"
              src={mod.image}
            />
          </div>
          <div>
            <h2 class="text-lg font-bold">
              {mod.name}{' '}
              <span class="ml-1 text-sm font-normal">
                {translations.by} @{mod.author}
              </span>
            </h2>
            <p class="line-clamp-2 text-sm font-thin">{mod.description}</p>
          </div>
        </a>
      ))
    }
  </div>
  <div
    id="no-results"
    class="hidden h-full min-h-96 flex-col justify-center gap-4 place-self-center text-center"
  >
    <h2 class="text-lg font-bold">{translations.noResults}</h2>
    <p class="text-sm font-thin">{translations.noResultsDescription}</p>
  </div>
  <div id="pagination" class="mx-auto mb-12 hidden items-center justify-center gap-4 px-8">
    {
      totalPages > 1 && (
        <>
          <span class="pointer-events-none px-3 py-2 text-gray-400">&lt;</span>
          <form class="flex items-center gap-2" id="page-form">
            <input
              id="page-input"
              aria-label="Page number"
              class="w-16 rounded border border-dark bg-transparent px-2 py-1 text-center text-sm"
              type="text"
              value="1"
            />
            <span class="text-sm">
              {translations.pagination.pagination
                .replace('{totalPages}', totalPages.toString())
                .replace('{totalItems}', allMods.length.toString())
                .replace('{input}', '')}
            </span>
          </form>
          <a
            class="px-3 py-2 text-dark hover:text-gray-600"
            href={getLocalePath('/mods?page=2')}
            data-page="2"
          >
            &gt;
          </a>
        </>
      )
    }
  </div>
</div>

<script define:vars={{ allMods, translations, locale }} is:inline>
  class ModsSearch {
    constructor() {
      this.allMods = allMods
      this.translations = translations
      this.locale = locale // State
      this.state = {
        search: '',
        createdSort: 'default',
        updatedSort: 'default',
        page: 1,
        limit: 12,
      }

      // Track if content has been dynamically modified
      this.hasBeenModified = false

      // Performance optimizations
      this.searchTimeout = null
      this.isRendering = false
      this.lastFilteredMods = null
      this.lastRenderState = null

      // Cache DOM elements for better performance and intellisense
      this.elements = this.cacheElements()

      this.initializeFromURL()
      this.bindEvents()
      this.renderMods()
    }

    cacheElements() {
      const searchInput = document.getElementById('search')
      const limitSelect = document.getElementById('limit')
      const createdSortButton = document.getElementById('created-sort')
      const updatedSortButton = document.getElementById('updated-sort')
      const modsGrid = document.getElementById('mods-grid')
      const noResults = document.getElementById('no-results')
      const pagination = document.getElementById('pagination')
      const clearSearchButton = document.getElementById('clear-search')

      // Sort icon elements
      const createdSortDefault = document.getElementById('created-sort-default')
      const createdSortAsc = document.getElementById('created-sort-asc')
      const createdSortDesc = document.getElementById('created-sort-desc')
      const updatedSortDefault = document.getElementById('updated-sort-default')
      const updatedSortAsc = document.getElementById('updated-sort-asc')
      const updatedSortDesc = document.getElementById('updated-sort-desc')

      return {
        searchInput: searchInput instanceof HTMLInputElement ? searchInput : null,
        limitSelect: limitSelect instanceof HTMLSelectElement ? limitSelect : null,
        createdSortButton:
          createdSortButton instanceof HTMLButtonElement ? createdSortButton : null,
        updatedSortButton:
          updatedSortButton instanceof HTMLButtonElement ? updatedSortButton : null,
        modsGrid: modsGrid instanceof HTMLDivElement ? modsGrid : null,
        noResults: noResults instanceof HTMLDivElement ? noResults : null,
        pagination: pagination instanceof HTMLDivElement ? pagination : null,
        sortIcons: {
          createdDefault: createdSortDefault instanceof HTMLSpanElement ? createdSortDefault : null,
          createdAsc: createdSortAsc instanceof HTMLSpanElement ? createdSortAsc : null,
          createdDesc: createdSortDesc instanceof HTMLSpanElement ? createdSortDesc : null,
          updatedDefault: updatedSortDefault instanceof HTMLSpanElement ? updatedSortDefault : null,
          updatedAsc: updatedSortAsc instanceof HTMLSpanElement ? updatedSortAsc : null,
          updatedDesc: updatedSortDesc instanceof HTMLSpanElement ? updatedSortDesc : null,
        },
        clearSearchButton:
          clearSearchButton instanceof HTMLButtonElement ? clearSearchButton : null,
      }
    }

    getLocalePath(path) {
      if (this.locale && this.locale !== 'en' && !path.startsWith(`/${this.locale}`)) {
        return `/${this.locale}${path.startsWith('/') ? '' : '/'}${path}`
      }
      return path
    }
    validateSortOrder(value, defaultValue = 'default') {
      const validSortOrders = ['default', 'asc', 'desc']
      return validSortOrders.includes(value) ? value : defaultValue
    }

    validateLimit(value, defaultValue = 12) {
      const validLimits = [12, 24, 48, 96]
      const parsed = parseInt(value, 10)
      return validLimits.includes(parsed) ? parsed : defaultValue
    }

    validatePage(value, defaultValue = 1) {
      const parsed = parseInt(value, 10)
      return !isNaN(parsed) && parsed >= 1 ? parsed : defaultValue
    }
    initializeFromURL() {
      const params = new URLSearchParams(window.location.search)

      const rawCreatedSort = params.get('created')
      const rawUpdatedSort = params.get('updated')
      const rawPage = params.get('page')
      const rawLimit = params.get('limit')

      this.state = {
        search: params.get('q') || '',
        createdSort: this.validateSortOrder(rawCreatedSort, 'default'),
        updatedSort: this.validateSortOrder(rawUpdatedSort, 'default'),
        page: this.validatePage(rawPage, 1),
        limit: this.validateLimit(rawLimit, 12),
      }

      // Set form values using cached elements
      if (this.elements.searchInput) {
        this.elements.searchInput.value = this.state.search
      }
      if (this.elements.limitSelect) {
        this.elements.limitSelect.value = this.state.limit.toString()
      }
    }
    bindEvents() {
      // Search input with debouncing
      if (this.elements.searchInput) {
        this.elements.searchInput.addEventListener('input', e => {
          // Clear existing timeout
          if (this.searchTimeout) {
            clearTimeout(this.searchTimeout)
          }

          // Set new timeout for debounced search
          this.searchTimeout = setTimeout(() => {
            if (e.target instanceof HTMLInputElement) {
              this.setState({ search: e.target.value, page: 1 })
            }
          }, 300) // 300ms debounce
        })
        if (this.elements.clearSearchButton) {
          this.elements.searchInput.addEventListener('input', () => {
            if (this.elements.searchInput.value.trim() === '') {
              this.elements.clearSearchButton.classList.add('hidden')
            } else {
              this.elements.clearSearchButton.classList.remove('hidden')
            }
          })
          // Clear search
          this.elements.clearSearchButton.addEventListener('click', () => {
            this.elements.searchInput.value = ''
            this.setState({ search: '', page: 1 })
            this.elements.clearSearchButton.classList.add('hidden')
          })
        }
      }

      // Sort buttons
      if (this.elements.createdSortButton) {
        this.elements.createdSortButton.addEventListener('click', () => {
          this.toggleCreatedSort()
        })
      }

      if (this.elements.updatedSortButton) {
        this.elements.updatedSortButton.addEventListener('click', () => {
          this.toggleUpdatedSort()
        })
      }

      // Limit select
      if (this.elements.limitSelect) {
        this.elements.limitSelect.addEventListener('change', e => {
          if (e.target instanceof HTMLSelectElement) {
            const newLimit = this.validateLimit(e.target.value, this.state.limit)
            this.setState({ limit: newLimit, page: 1 })
          }
        })
      }
    }
    setState(newState) {
      // Prevent multiple renders
      if (this.isRendering) return

      // Validate new state values before setting
      const validatedState = { ...newState }

      if ('createdSort' in validatedState) {
        validatedState.createdSort = this.validateSortOrder(
          validatedState.createdSort,
          this.state.createdSort
        )
      }
      if ('updatedSort' in validatedState) {
        validatedState.updatedSort = this.validateSortOrder(
          validatedState.updatedSort,
          this.state.updatedSort
        )
      }

      if ('page' in validatedState) {
        validatedState.page = this.validatePage(validatedState.page, this.state.page)
      }

      if ('limit' in validatedState) {
        validatedState.limit = this.validateLimit(validatedState.limit, this.state.limit)
      }

      // Determine if this is a search/filter operation (should replace URL)
      // vs pagination navigation (should push to history)
      const isSearchOrFilter =
        'search' in validatedState ||
        'createdSort' in validatedState ||
        'updatedSort' in validatedState ||
        'limit' in validatedState ||
        ('page' in validatedState && validatedState.page === 1)

      this.state = { ...this.state, ...validatedState }
      this.updateURL(isSearchOrFilter)
      this.updateSortIcons()
      this.renderMods()
    }
    toggleCreatedSort() {
      const newSort =
        this.state.createdSort === 'default'
          ? 'asc'
          : this.state.createdSort === 'asc'
            ? 'desc'
            : 'default'
      this.setState({ createdSort: newSort, updatedSort: 'default', page: 1 })
    }

    toggleUpdatedSort() {
      const newSort =
        this.state.updatedSort === 'default'
          ? 'asc'
          : this.state.updatedSort === 'asc'
            ? 'desc'
            : 'default'
      this.setState({ updatedSort: newSort, createdSort: 'default', page: 1 })
    }
    updateSortIcons() {
      // Update created sort icons using cached elements
      if (this.elements.sortIcons.createdDefault) {
        this.elements.sortIcons.createdDefault.classList.toggle(
          'hidden',
          this.state.createdSort !== 'default'
        )
      }
      if (this.elements.sortIcons.createdAsc) {
        this.elements.sortIcons.createdAsc.classList.toggle(
          'hidden',
          this.state.createdSort !== 'asc'
        )
      }
      if (this.elements.sortIcons.createdDesc) {
        this.elements.sortIcons.createdDesc.classList.toggle(
          'hidden',
          this.state.createdSort !== 'desc'
        )
      }

      // Update updated sort icons using cached elements
      if (this.elements.sortIcons.updatedDefault) {
        this.elements.sortIcons.updatedDefault.classList.toggle(
          'hidden',
          this.state.updatedSort !== 'default'
        )
      }
      if (this.elements.sortIcons.updatedAsc) {
        this.elements.sortIcons.updatedAsc.classList.toggle(
          'hidden',
          this.state.updatedSort !== 'asc'
        )
      }
      if (this.elements.sortIcons.updatedDesc) {
        this.elements.sortIcons.updatedDesc.classList.toggle(
          'hidden',
          this.state.updatedSort !== 'desc'
        )
      }
    }
    updateURL(isSearchOrFilter = false) {
      const params = new URLSearchParams()

      if (this.state.search) params.set('q', this.state.search)
      if (this.state.createdSort !== 'default') params.set('created', this.state.createdSort)
      if (this.state.updatedSort !== 'default') params.set('updated', this.state.updatedSort)
      if (this.state.page > 1) params.set('page', this.state.page.toString())
      if (this.state.limit !== 12) params.set('limit', this.state.limit.toString())

      const newUrl = `${window.location.pathname}${params.toString() ? `?${params.toString()}` : ''}`

      // Only push to history for pagination navigation, replace for search/filtering
      if (!isSearchOrFilter && this.state.page > 1) {
        window.history.pushState({}, '', newUrl)
      } else {
        window.history.replaceState({}, '', newUrl)
      }
    }

    getFilteredMods() {
      let filtered = [...this.allMods]

      // Filter by search
      const searchTerm = this.state.search.toLowerCase()
      if (searchTerm) {
        filtered = filtered.filter(
          mod =>
            mod.name.toLowerCase().includes(searchTerm) ||
            mod.description.toLowerCase().includes(searchTerm) ||
            mod.author.toLowerCase().includes(searchTerm) ||
            (mod.tags?.some(tag => tag.toLowerCase().includes(searchTerm)) ?? false)
        )
      }

      // Sort by createdAt if chosen
      if (this.state.createdSort !== 'default') {
        filtered.sort((a, b) => {
          const diff = new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
          return this.state.createdSort === 'asc' ? diff : -diff
        })
      }

      // Sort by updatedAt if chosen
      if (this.state.updatedSort !== 'default') {
        filtered.sort((a, b) => {
          const diff = new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime()
          return this.state.updatedSort === 'asc' ? diff : -diff
        })
      }

      return filtered
    }
    renderMods() {
      // Prevent concurrent renders
      if (this.isRendering) return
      this.isRendering = true

      // Use requestAnimationFrame for smoother rendering
      requestAnimationFrame(() => {
        try {
          const filteredMods = this.getFilteredMods()
          const totalPages = Math.ceil(filteredMods.length / this.state.limit)
          const startIndex = (this.state.page - 1) * this.state.limit
          const endIndex = startIndex + this.state.limit
          const paginatedMods = filteredMods.slice(startIndex, endIndex)

          if (paginatedMods.length > 0) {
            if (this.elements.noResults) {
              this.elements.noResults.classList.add('hidden')
            }
            if (this.elements.modsGrid) {
              this.elements.modsGrid.classList.remove('hidden')
            }

            // Check if we're in the default state
            const isDefaultState =
              this.state.search === '' &&
              this.state.createdSort === 'default' &&
              this.state.updatedSort === 'default' &&
              this.state.page === 1 &&
              this.state.limit === 12

            // Re-render if: not in default state, OR we've been modified and need to restore default
            if (!isDefaultState || this.hasBeenModified) {
              // Create document fragment for better performance
              const fragment = document.createDocumentFragment()
              const tempDiv = document.createElement('div')

              tempDiv.innerHTML = paginatedMods
                .map(
                  mod => `
                <a
                  class="mod-card flex w-full flex-col gap-4 border-transparent transition-colors duration-100 hover:opacity-90"
                  href="${this.getLocalePath(`/mods/${mod.id}${this.buildSearchParams()}`)}"
                >
                  <div class="relative mb-0 block aspect-[1.85/1] h-48 overflow-hidden rounded-md border-2 border-dark object-cover shadow-md">
                    <img
                      alt="${mod.name}"
                      class="h-full w-full object-cover transition-transform duration-100 hover:scale-105"
                      loading="lazy"
                      src="${mod.image}"
                    />
                  </div>
                  <div>
                    <h2 class="text-lg font-bold">
                      ${mod.name} <span class="ml-1 text-sm font-normal">${this.translations.by} @${mod.author}</span>
                    </h2>
                    <p class="text-sm font-thin line-clamp-2">${mod.description}</p>
                  </div>
                </a>
              `
                )
                .join('')

              // Move all children to fragment
              while (tempDiv.firstChild) {
                fragment.appendChild(tempDiv.firstChild)
              }

              // Clear and append fragment (single reflow)
              if (this.elements.modsGrid) {
                this.elements.modsGrid.innerHTML = ''
                this.elements.modsGrid.appendChild(fragment)
              }

              // Track that we've modified the content
              this.hasBeenModified = !isDefaultState
            }
          } else {
            if (this.elements.modsGrid) {
              this.elements.modsGrid.classList.add('hidden')
            }
            if (this.elements.noResults) {
              this.elements.noResults.classList.replace('hidden', 'flex')
            }
            this.hasBeenModified = true
          }

          this.renderPagination(totalPages, filteredMods.length)
        } finally {
          this.isRendering = false
        }
      })
    }

    buildSearchParams() {
      const params = new URLSearchParams()
      if (this.state.search) params.set('q', this.state.search)
      if (this.state.createdSort !== 'default') params.set('created', this.state.createdSort)
      if (this.state.updatedSort !== 'default') params.set('updated', this.state.updatedSort)
      if (this.state.page > 1) params.set('page', this.state.page.toString())
      if (this.state.limit !== 12) params.set('limit', this.state.limit.toString())
      return params.toString() ? `?${params.toString()}` : ''
    }

    buildPaginationUrl(targetPage) {
      const params = new URLSearchParams(this.buildSearchParams())
      if (targetPage > 1) {
        params.set('page', targetPage.toString())
      } else {
        params.delete('page')
      }
      return `/mods?${params.toString()}`
    }
    navigatePage(pageNum) {
      // Validate page number
      const validatedPage = this.validatePage(pageNum, this.state.page)

      // Update state without going through setState to handle URL properly
      this.state = { ...this.state, page: validatedPage }

      // For pagination navigation, push to history if page > 1, otherwise replace
      this.updateURL(false) // false = this is navigation, not search/filter
      this.updateSortIcons()
      this.renderMods()
      window.scrollTo(0, 0)
    }

    renderPagination(totalPages, totalItems) {
      const paginationElement = this.elements.pagination

      if (!paginationElement) return

      if (totalPages <= 1) {
        paginationElement.innerHTML = ''
        paginationElement.classList.add('hidden')
        return
      }

      const prevButton =
        this.state.page > 1
          ? `<a
          class="px-3 py-2 text-dark hover:text-gray-600"
          href="${this.getLocalePath(this.buildPaginationUrl(this.state.page - 1))}"
          data-page="${this.state.page - 1}"
        >
          &lt;
        </a>`
          : `<span class="pointer-events-none px-3 py-2 text-gray-400">&lt;</span>`

      const nextButton =
        this.state.page < totalPages
          ? `<a
          class="px-3 py-2 text-dark hover:text-gray-600"
          href="${this.getLocalePath(this.buildPaginationUrl(this.state.page + 1))}"
          data-page="${this.state.page + 1}"
        >
          &gt;
        </a>`
          : `<span class="pointer-events-none px-3 py-2 text-gray-400">&gt;</span>`

      const paginationText = this.translations.pagination.pagination
        .replace('{totalPages}', totalPages.toString())
        .replace('{totalItems}', totalItems.toString())

      paginationElement.innerHTML = `
        ${prevButton}
        <form class="flex items-center gap-2" id="page-form">
          <input
            id="page-input"
            aria-label="Page number"
            class="w-16 rounded border border-dark bg-transparent px-2 py-1 text-center text-sm"
            type="text"
            value="${this.state.page}"
          />
          <span class="text-sm">${paginationText.replace('{input}', '')}</span>
        </form>
        ${nextButton}
      `

      // Bind pagination events
      paginationElement.classList.replace('hidden', 'flex')

      const pageForm = document.getElementById('page-form')
      const pageInput = document.getElementById('page-input')

      if (pageForm && pageInput instanceof HTMLInputElement) {
        pageForm.addEventListener('submit', e => {
          e.preventDefault()
          const inputValue = pageInput.value
          const newPage = this.validatePage(inputValue, this.state.page)

          // Additional validation for page range
          if (newPage >= 1 && newPage <= totalPages) {
            this.navigatePage(newPage)
          } else {
            // Reset to current page if out of range
            pageInput.value = this.state.page.toString()
          }
        })
      }

      // Bind navigation links
      paginationElement.addEventListener('click', e => {
        if (e.target instanceof HTMLAnchorElement && e.target.dataset.page) {
          e.preventDefault()
          this.navigatePage(parseInt(e.target.dataset.page, 10))
        }
      })
    }
  }

  // Initialize the mods search
  new ModsSearch()
</script>
