import { Pagination } from 'components/Pagination'
import { kinds, nip19 } from 'nostr-tools'
import React, {
  Dispatch,
  SetStateAction,
  useCallback,
  useEffect,
  useMemo,
  useState
} from 'react'
import { LoadingSpinner } from '../components/LoadingSpinner'
import { ModCard } from '../components/ModCard'
import { MOD_FILTER_LIMIT } from '../constants'
import { MetadataController } from '../controllers'
import { useAppSelector, useDidMount, useMuteLists } from '../hooks'
import { getModPageRoute } from '../routes'
import '../styles/filters.css'
import '../styles/pagination.css'
import '../styles/search.css'
import '../styles/styles.css'
import { ModDetails } from '../types'
import { fetchMods } from '../utils'

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

enum NSFWFilter {
  Hide_NSFW = 'Hide NSFW',
  Show_NSFW = 'Show NSFW',
  Only_NSFW = 'Only NSFW'
}

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

interface FilterOptions {
  sort: SortBy
  nsfw: NSFWFilter
  source: string
  moderated: ModeratedFilter
}

export const ModsPage = () => {
  const [isFetching, setIsFetching] = useState(false)
  const [mods, setMods] = useState<ModDetails[]>([])
  const [filterOptions, setFilterOptions] = useState<FilterOptions>({
    sort: SortBy.Latest,
    nsfw: NSFWFilter.Hide_NSFW,
    source: window.location.host,
    moderated: ModeratedFilter.Moderated
  })
  const muteLists = useMuteLists()

  const [nsfwList, setNSFWList] = useState<string[]>([])

  const [page, setPage] = useState(1)

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

  useDidMount(async () => {
    const metadataController = await MetadataController.getInstance()

    metadataController.getNSFWList().then((list) => {
      setNSFWList(list)
    })
  })

  useEffect(() => {
    setIsFetching(true)
    fetchMods({ source: filterOptions.source })
      .then((res) => {
        setMods(res)
      })
      .finally(() => {
        setIsFetching(false)
      })
  }, [filterOptions.source])

  const handleNext = useCallback(() => {
    setIsFetching(true)

    const until =
      mods.length > 0 ? mods[mods.length - 1].published_at - 1 : undefined

    fetchMods({
      source: filterOptions.source,
      until
    })
      .then((res) => {
        setMods(res)
        setPage((prev) => prev + 1)
      })
      .finally(() => {
        setIsFetching(false)
      })
  }, [filterOptions.source, mods])

  const handlePrev = useCallback(() => {
    setIsFetching(true)

    const since = mods.length > 0 ? mods[0].published_at + 1 : undefined

    fetchMods({
      source: filterOptions.source,
      since
    })
      .then((res) => {
        setMods(res)
        setPage((prev) => prev - 1)
      })
      .finally(() => {
        setIsFetching(false)
      })
  }, [filterOptions.source, mods])

  const filteredModList = useMemo(() => {
    const nsfwFilter = (mods: ModDetails[]) => {
      // Determine the filtering logic based on the NSFW filter option
      switch (filterOptions.nsfw) {
        case NSFWFilter.Hide_NSFW:
          // If 'Hide_NSFW' is selected, filter out NSFW mods
          return mods.filter((mod) => !mod.nsfw && !nsfwList.includes(mod.aTag))
        case NSFWFilter.Show_NSFW:
          // If 'Show_NSFW' is selected, return all mods (no filtering)
          return mods
        case NSFWFilter.Only_NSFW:
          // If 'Only_NSFW' is selected, filter to show only NSFW mods
          return mods.filter((mod) => mod.nsfw || nsfwList.includes(mod.aTag))
      }
    }

    let filtered = nsfwFilter(mods)

    const isAdmin = userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB
    const isUnmoderatedFully =
      filterOptions.moderated === ModeratedFilter.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 === ModeratedFilter.Moderated) {
      filtered = filtered.filter(
        (mod) =>
          !muteLists.user.authors.includes(mod.author) &&
          !muteLists.user.replaceableEvents.includes(mod.aTag)
      )
    }

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

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

  return (
    <>
      {isFetching && <LoadingSpinner desc='Fetching mod details from relays' />}
      <div className='InnerBodyMain'>
        <div className='ContainerMain'>
          <div className='IBMSecMainGroup IBMSecMainGroupAlt'>
            <PageTitleRow />
            <Filters
              filterOptions={filterOptions}
              setFilterOptions={setFilterOptions}
            />

            <div className='IBMSecMain IBMSMListWrapper'>
              <div className='IBMSMList'>
                {filteredModList.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>

            <Pagination
              page={page}
              disabledNext={mods.length < MOD_FILTER_LIMIT}
              handlePrev={handlePrev}
              handleNext={handleNext}
            />
          </div>
        </div>
      </div>
    </>
  )
}

const PageTitleRow = React.memo(() => {
  return (
    <div className='IBMSecMain'>
      <div className='SearchMainWrapper'>
        <div className='IBMSMTitleMain'>
          <h2 className='IBMSMTitleMainHeading'>Mods</h2>
        </div>
        <div className='SearchMain'>
          <div className='SearchMainInside'>
            <div className='SearchMainInsideWrapper'>
              <input type='text' className='SMIWInput' />
              <button className='btn btnMain SMIWButton' type='button'>
                <svg
                  xmlns='http://www.w3.org/2000/svg'
                  viewBox='0 0 512 512'
                  width='1em'
                  height='1em'
                  fill='currentColor'
                >
                  <path d='M500.3 443.7l-119.7-119.7c27.22-40.41 40.65-90.9 33.46-144.7C401.8 87.79 326.8 13.32 235.2 1.723C99.01-15.51-15.51 99.01 1.724 235.2c11.6 91.64 86.08 166.7 177.6 178.9c53.8 7.189 104.3-6.236 144.7-33.46l119.7 119.7c15.62 15.62 40.95 15.62 56.57 0C515.9 484.7 515.9 459.3 500.3 443.7zM79.1 208c0-70.58 57.42-128 128-128s128 57.42 128 128c0 70.58-57.42 128-128 128S79.1 278.6 79.1 208z'></path>
                </svg>
              </button>
            </div>
          </div>
        </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(SortBy).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(ModeratedFilter).map((item, index) => {
                  if (item === ModeratedFilter.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 className='FiltersMainElement'>
            <div className='dropdown dropdownMain'>
              <button
                className='btn dropdown-toggle btnMain btnMainDropdown'
                aria-expanded='false'
                data-bs-toggle='dropdown'
                type='button'
              >
                {filterOptions.nsfw}
              </button>
              <div className='dropdown-menu dropdownMainMenu'>
                {Object.values(NSFWFilter).map((item, index) => (
                  <div
                    key={`nsfwFilterItem-${index}`}
                    className='dropdown-item dropdownMainMenuItem'
                    onClick={() =>
                      setFilterOptions((prev) => ({
                        ...prev,
                        nsfw: 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.source === window.location.host
                  ? `Show From: ${filterOptions.source}`
                  : 'Show All'}
              </button>
              <div className='dropdown-menu dropdownMainMenu'>
                <div
                  className='dropdown-item dropdownMainMenuItem'
                  onClick={() =>
                    setFilterOptions((prev) => ({
                      ...prev,
                      source: window.location.host
                    }))
                  }
                >
                  Show From: {window.location.host}
                </div>
                <div
                  className='dropdown-item dropdownMainMenuItem'
                  onClick={() =>
                    setFilterOptions((prev) => ({
                      ...prev,
                      source: 'Show All'
                    }))
                  }
                >
                  Show All
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
)
