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

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'
}

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

export const ModsPage = () => {
  const navigate = useNavigate()
  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, setMuteLists] = useState<MuteLists>({
    authors: [],
    eventIds: []
  })

  const [page, setPage] = useState(1)

  useDidMount(async () => {
    const metadataController = await MetadataController.getInstance()
    metadataController.getAdminsMuteLists().then((lists) => {
      setMuteLists(lists)
    })
  })

  useEffect(() => {
    setIsFetching(true)
    fetchMods(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].edited_at - 1 : undefined

    fetchMods(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].edited_at + 1 : undefined

    fetchMods(filterOptions.source, undefined, 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)
        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)
      }
    }

    let filtered = nsfwFilter(mods)

    if (filterOptions.moderated === ModeratedFilter.Moderated) {
      filtered = filtered.filter(
        (mod) =>
          !muteLists.authors.includes(mod.author) &&
          !muteLists.eventIds.includes(mod.id)
      )
    }

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

    return filtered
  }, [
    filterOptions.sort,
    filterOptions.moderated,
    filterOptions.nsfw,
    mods,
    muteLists
  ])

  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) => (
                  <ModCard
                    key={mod.id}
                    title={mod.title}
                    summary={mod.summary}
                    backgroundLink={mod.featuredImageUrl}
                    handleClick={() =>
                      navigate(
                        getModsInnerPageRoute(
                          nip19.naddrEncode({
                            identifier: mod.aTag,
                            pubkey: mod.author,
                            kind: kinds.ClassifiedListing
                          })
                        )
                      )
                    }
                  />
                ))}
              </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) => {
    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) => (
                  <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>
    )
  }
)

type PaginationProps = {
  page: number
  disabledNext: boolean
  handlePrev: () => void
  handleNext: () => void
}

const Pagination = React.memo(
  ({ page, disabledNext, handlePrev, handleNext }: PaginationProps) => {
    return (
      <div className='IBMSecMain'>
        <div className='PaginationMain'>
          <div className='PaginationMainInside'>
            <button
              className='PaginationMainInsideBox PaginationMainInsideBoxArrows'
              onClick={handlePrev}
              disabled={page === 1}
            >
              <i className='fas fa-chevron-left'></i>
            </button>
            <div className='PaginationMainInsideBoxGroup'>
              <button className='PaginationMainInsideBox PMIBActive'>
                <p>{page}</p>
              </button>
            </div>
            <button
              className='PaginationMainInsideBox PaginationMainInsideBoxArrows'
              onClick={handleNext}
              disabled={disabledNext}
            >
              <i className='fas fa-chevron-right'></i>
            </button>
          </div>
        </div>
      </div>
    )
  }
)
