import { LoadingSpinner } from 'components/LoadingSpinner'
import { ModCard } from 'components/ModCard'
import { PaginationWithPageNumbers } from 'components/Pagination'
import { MAX_MODS_PER_PAGE, T_TAG_VALUE } from 'constants.ts'
import { RelayController } from 'controllers'
import { useAppSelector, useMuteLists } from 'hooks'
import { Filter, kinds, nip19 } from 'nostr-tools'
import { Subscription } from 'nostr-tools/abstract-relay'
import React, {
  Dispatch,
  SetStateAction,
  useEffect,
  useMemo,
  useRef,
  useState
} from 'react'
import { useParams } from 'react-router-dom'
import { toast } from 'react-toastify'
import { getModPageRoute } from 'routes'
import { ModDetails } from 'types'
import { extractModData, isModDataComplete, log, LogType } from 'utils'

enum SortByEnum {
  Latest = 'Latest',
  Oldest = 'Oldest',
  Best_Rated = 'Best Rated',
  Worst_Rated = 'Worst Rated'
}

enum ModeratedFilterEnum {
  Moderated = 'Moderated',
  Unmoderated = 'Unmoderated',
  Unmoderated_Fully = 'Unmoderated Fully'
}

interface FilterOptions {
  sort: SortByEnum
  moderated: ModeratedFilterEnum
}

export const GamePage = () => {
  const params = useParams()
  const { name: gameName } = params
  const muteLists = useMuteLists()

  const [filterOptions, setFilterOptions] = useState<FilterOptions>({
    sort: SortByEnum.Latest,
    moderated: ModeratedFilterEnum.Moderated
  })
  const [mods, setMods] = useState<ModDetails[]>([])

  const hasEffectRun = useRef(false)
  const [isSubscribing, setIsSubscribing] = useState(false)
  const [currentPage, setCurrentPage] = useState(1)

  const userState = useAppSelector((state) => state.user)

  const filteredMods = useMemo(() => {
    let filtered: ModDetails[] = [...mods]
    const isAdmin = userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB
    const isUnmoderatedFully =
      filterOptions.moderated === ModeratedFilterEnum.Unmoderated_Fully

    // Only apply filtering if the user is not an admin or the admin has not selected "Unmoderated Fully"
    if (!(isAdmin && isUnmoderatedFully)) {
      filtered = filtered.filter(
        (mod) =>
          !muteLists.admin.authors.includes(mod.author) &&
          !muteLists.admin.replaceableEvents.includes(mod.aTag)
      )
    }

    if (filterOptions.moderated === ModeratedFilterEnum.Moderated) {
      filtered = filtered.filter(
        (mod) =>
          !muteLists.user.authors.includes(mod.author) &&
          !muteLists.user.replaceableEvents.includes(mod.aTag)
      )
    }

    if (filterOptions.sort === SortByEnum.Latest) {
      filtered.sort((a, b) => b.published_at - a.published_at)
    } else if (filterOptions.sort === SortByEnum.Oldest) {
      filtered.sort((a, b) => a.published_at - b.published_at)
    }

    return filtered
  }, [
    mods,
    userState.user?.npub,
    filterOptions.sort,
    filterOptions.moderated,
    muteLists
  ])

  // Pagination logic
  const totalGames = filteredMods.length
  const totalPages = Math.ceil(totalGames / MAX_MODS_PER_PAGE)
  const startIndex = (currentPage - 1) * MAX_MODS_PER_PAGE
  const endIndex = startIndex + MAX_MODS_PER_PAGE
  const currentMods = filteredMods.slice(startIndex, endIndex)

  const handlePageChange = (page: number) => {
    if (page >= 1 && page <= totalPages) {
      setCurrentPage(page)
    }
  }

  useEffect(() => {
    if (hasEffectRun.current) {
      return
    }

    hasEffectRun.current = true // Set it so the effect doesn't run again

    const filter: Filter = {
      kinds: [kinds.ClassifiedListing],
      '#t': [T_TAG_VALUE]
    }

    setIsSubscribing(true)

    let subscriptions: Subscription[] = []

    RelayController.getInstance()
      .subscribeForEvents(filter, [], (event) => {
        if (isModDataComplete(event)) {
          const mod = extractModData(event)
          if (mod.game === gameName) setMods((prev) => [...prev, mod])
        }
      })
      .then((subs) => {
        subscriptions = subs
      })
      .catch((err) => {
        log(
          true,
          LogType.Error,
          'An error occurred in subscribing to relays.',
          err
        )
        toast.error(err.message || err)
      })
      .finally(() => {
        setIsSubscribing(false)
      })

    // Cleanup function to stop all subscriptions
    return () => {
      subscriptions.forEach((sub) => sub.close()) // close each subscription
    }
  }, [gameName])

  if (!gameName) return null

  return (
    <>
      {isSubscribing && (
        <LoadingSpinner desc='Subscribing to relays for mods' />
      )}
      <div className='InnerBodyMain'>
        <div className='ContainerMain'>
          <div className='IBMSecMainGroup IBMSecMainGroupAlt'>
            <div className='IBMSecMain'>
              <div className='SearchMainWrapper'>
                <div className='IBMSMTitleMain'>
                  <h2 className='IBMSMTitleMainHeading'>
                    Game:&nbsp;
                    <span className='IBMSMTitleMainHeadingSpan'>
                      {gameName}
                    </span>
                  </h2>
                </div>
              </div>
            </div>
            <Filters
              filterOptions={filterOptions}
              setFilterOptions={setFilterOptions}
            />
            <div className='IBMSecMain IBMSMListWrapper'>
              <div className='IBMSMList'>
                {currentMods.map((mod) => {
                  const route = getModPageRoute(
                    nip19.naddrEncode({
                      identifier: mod.aTag,
                      pubkey: mod.author,
                      kind: kinds.ClassifiedListing
                    })
                  )

                  return (
                    <ModCard
                      key={mod.id}
                      title={mod.title}
                      gameName={mod.game}
                      summary={mod.summary}
                      imageUrl={mod.featuredImageUrl}
                      route={route}
                    />
                  )
                })}
              </div>
            </div>
            <PaginationWithPageNumbers
              currentPage={currentPage}
              totalPages={totalPages}
              handlePageChange={handlePageChange}
            />
          </div>
        </div>
      </div>
    </>
  )
}

type FiltersProps = {
  filterOptions: FilterOptions
  setFilterOptions: Dispatch<SetStateAction<FilterOptions>>
}

const Filters = React.memo(
  ({ filterOptions, setFilterOptions }: FiltersProps) => {
    const userState = useAppSelector((state) => state.user)

    return (
      <div className='IBMSecMain'>
        <div className='FiltersMain'>
          <div className='FiltersMainElement'>
            <div className='dropdown dropdownMain'>
              <button
                className='btn dropdown-toggle btnMain btnMainDropdown'
                aria-expanded='false'
                data-bs-toggle='dropdown'
                type='button'
              >
                {filterOptions.sort}
              </button>

              <div className='dropdown-menu dropdownMainMenu'>
                {Object.values(SortByEnum).map((item, index) => (
                  <div
                    key={`sortByItem-${index}`}
                    className='dropdown-item dropdownMainMenuItem'
                    onClick={() =>
                      setFilterOptions((prev) => ({
                        ...prev,
                        sort: item
                      }))
                    }
                  >
                    {item}
                  </div>
                ))}
              </div>
            </div>
          </div>
          <div className='FiltersMainElement'>
            <div className='dropdown dropdownMain'>
              <button
                className='btn dropdown-toggle btnMain btnMainDropdown'
                aria-expanded='false'
                data-bs-toggle='dropdown'
                type='button'
              >
                {filterOptions.moderated}
              </button>
              <div className='dropdown-menu dropdownMainMenu'>
                {Object.values(ModeratedFilterEnum).map((item, index) => {
                  if (item === ModeratedFilterEnum.Unmoderated_Fully) {
                    const isAdmin =
                      userState.user?.npub ===
                      import.meta.env.VITE_REPORTING_NPUB

                    if (!isAdmin) return null
                  }

                  return (
                    <div
                      key={`moderatedFilterItem-${index}`}
                      className='dropdown-item dropdownMainMenuItem'
                      onClick={() =>
                        setFilterOptions((prev) => ({
                          ...prev,
                          moderated: item
                        }))
                      }
                    >
                      {item}
                    </div>
                  )
                })}
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
)
