import { Answer } from 'common/answer'
import { searchInAny } from 'common/util/parse'
import { sortBy } from 'lodash'
import { useState } from 'react'
import { ContractsGrid } from 'web/components/contract/contracts-list'
import { LoadingIndicator } from 'web/components/loading-indicator'
import { useContracts } from 'web/hooks/use-contracts'
import {
  Sort,
  useInitialQueryAndSort,
} from 'web/hooks/use-sort-and-query-params'

const MAX_CONTRACTS_RENDERED = 100

export default function ContractSearchFirestore(props: {
  querySortOptions?: {
    defaultSort: Sort
    shouldLoadFromStorage?: boolean
  }
  additionalFilter?: {
    creatorId?: string
    tag?: string
  }
}) {
  const contracts = useContracts()
  const { querySortOptions, additionalFilter } = props

  const { initialSort, initialQuery } = useInitialQueryAndSort(querySortOptions)
  const [sort, setSort] = useState(initialSort || 'newest')
  const [query, setQuery] = useState(initialQuery)

  let matches = (contracts ?? []).filter((c) =>
    searchInAny(
      query,
      c.question,
      c.creatorName,
      c.lowercaseTags.map((tag) => `#${tag}`).join(' '),
      ((c as any).answers ?? []).map((answer: Answer) => answer.text).join(' ')
    )
  )

  if (sort === 'newest') {
    matches.sort((a, b) => b.createdTime - a.createdTime)
  } else if (sort === 'resolve-date') {
    matches = sortBy(matches, (contract) => -1 * (contract.resolutionTime ?? 0))
  } else if (sort === 'oldest') {
    matches.sort((a, b) => a.createdTime - b.createdTime)
  } else if (sort === 'close-date') {
    matches = sortBy(matches, ({ volume24Hours }) => -1 * volume24Hours)
    matches = sortBy(
      matches,
      (contract) =>
        (sort === 'close-date' ? -1 : 1) * (contract.closeTime ?? Infinity)
    )
  } else if (sort === 'most-traded') {
    matches.sort((a, b) => b.volume - a.volume)
  } else if (sort === 'score') {
    matches.sort((a, b) => (b.popularityScore ?? 0) - (a.popularityScore ?? 0))
  } else if (sort === '24-hour-vol') {
    // Use lodash for stable sort, so previous sort breaks all ties.
    matches = sortBy(matches, ({ volume7Days }) => -1 * volume7Days)
    matches = sortBy(matches, ({ volume24Hours }) => -1 * volume24Hours)
  }

  if (additionalFilter) {
    const { creatorId, tag } = additionalFilter

    if (creatorId) {
      matches = matches.filter((c) => c.creatorId === creatorId)
    }

    if (tag) {
      matches = matches.filter((c) =>
        c.lowercaseTags.includes(tag.toLowerCase())
      )
    }
  }

  matches = matches.slice(0, MAX_CONTRACTS_RENDERED)

  const showTime = ['close-date', 'closed'].includes(sort)
    ? 'close-date'
    : sort === 'resolve-date'
    ? 'resolve-date'
    : undefined

  return (
    <div>
      {/* Show a search input next to a sort dropdown */}
      <div className="mt-2 mb-8 flex justify-between gap-2">
        <input
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Search markets"
          className="input input-bordered w-full"
        />
        <select
          className="select select-bordered"
          value={sort}
          onChange={(e) => setSort(e.target.value as Sort)}
        >
          <option value="newest">Newest</option>
          <option value="oldest">Oldest</option>
          <option value="score">Most popular</option>
          <option value="most-traded">Most traded</option>
          <option value="24-hour-vol">24h volume</option>
          <option value="close-date">Closing soon</option>
        </select>
      </div>
      {contracts === undefined ? (
        <LoadingIndicator />
      ) : (
        <ContractsGrid
          contracts={matches}
          loadMore={() => {}}
          hasMore={false}
          showTime={showTime}
        />
      )}
    </div>
  )
}