import { sortBy, partition, sum } from 'lodash'
import { useEffect, useState } from 'react'

import { FreeResponseContract, MultipleChoiceContract } from 'common/contract'
import { Col } from '../layout/col'
import { useUser } from 'web/hooks/use-user'
import { getDpmOutcomeProbability } from 'common/calculate-dpm'
import { useAnswers } from 'web/hooks/use-answers'
import { tradingAllowed } from 'web/lib/firebase/contracts'
import { AnswerItem } from './answer-item'
import { CreateAnswerPanel } from './create-answer-panel'
import { AnswerResolvePanel } from './answer-resolve-panel'
import { Spacer } from '../layout/spacer'
import { getOutcomeProbability } from 'common/calculate'
import { Answer } from 'common/answer'
import clsx from 'clsx'
import { formatPercent } from 'common/util/format'
import { Modal } from 'web/components/layout/modal'
import { AnswerBetPanel } from 'web/components/answers/answer-bet-panel'
import { Row } from 'web/components/layout/row'
import { Avatar } from 'web/components/avatar'
import { Linkify } from 'web/components/linkify'
import { Button } from 'web/components/button'
import { useAdmin } from 'web/hooks/use-admin'
import { needsAdminToResolve } from 'web/pages/[username]/[contractSlug]'
import { CHOICE_ANSWER_COLORS } from '../charts/contract/choice'
import { useChartAnswers } from '../charts/contract/choice'
import { ChatIcon } from '@heroicons/react/outline'

export function AnswersPanel(props: {
  contract: FreeResponseContract | MultipleChoiceContract
  onAnswerCommentClick: (answer: Answer) => void
}) {
  const isAdmin = useAdmin()
  const { contract, onAnswerCommentClick } = props
  const { creatorId, resolution, resolutions, totalBets, outcomeType } =
    contract
  const [showAllAnswers, setShowAllAnswers] = useState(false)

  const answers = (useAnswers(contract.id) ?? contract.answers).filter(
    (a) => a.number != 0 || contract.outcomeType === 'MULTIPLE_CHOICE'
  )

  const hasZeroBetAnswers = answers.some((answer) => totalBets[answer.id] < 1)

  const [winningAnswers, losingAnswers] = partition(
    answers.filter((a) => (showAllAnswers ? true : totalBets[a.id] > 0)),
    (answer) =>
      answer.id === resolution || (resolutions && resolutions[answer.id])
  )
  const sortedAnswers = [
    ...sortBy(winningAnswers, (answer) =>
      resolutions ? -1 * resolutions[answer.id] : 0
    ),
    ...sortBy(
      resolution ? [] : losingAnswers,
      (answer) => -1 * getDpmOutcomeProbability(contract.totalShares, answer.id)
    ),
  ]

  const answerItems = sortBy(
    losingAnswers.length > 0 ? losingAnswers : sortedAnswers,
    (answer) => -getOutcomeProbability(contract, answer.id)
  )

  const user = useUser()

  const [resolveOption, setResolveOption] = useState<
    'CHOOSE' | 'CHOOSE_MULTIPLE' | 'CANCEL' | undefined
  >()
  const [chosenAnswers, setChosenAnswers] = useState<{
    [answerId: string]: number
  }>({})

  const chosenTotal = sum(Object.values(chosenAnswers))

  const onChoose = (answerId: string, prob: number) => {
    if (resolveOption === 'CHOOSE') {
      setChosenAnswers({ [answerId]: prob })
    } else {
      setChosenAnswers((chosenAnswers) => {
        return {
          ...chosenAnswers,
          [answerId]: prob,
        }
      })
    }
  }

  const onDeselect = (answerId: string) => {
    setChosenAnswers((chosenAnswers) => {
      const newChosenAnswers = { ...chosenAnswers }
      delete newChosenAnswers[answerId]
      return newChosenAnswers
    })
  }

  useEffect(() => {
    setChosenAnswers({})
  }, [resolveOption])

  const showChoice = resolution
    ? undefined
    : resolveOption === 'CHOOSE'
    ? 'radio'
    : resolveOption === 'CHOOSE_MULTIPLE'
    ? 'checkbox'
    : undefined

  const colorSortedAnswer = useChartAnswers(contract).map(
    (value, _index) => value.text
  )

  return (
    <Col className="gap-3">
      {(resolveOption || resolution) &&
        sortedAnswers.map((answer) => (
          <AnswerItem
            key={answer.id}
            answer={answer}
            contract={contract}
            showChoice={showChoice}
            chosenProb={chosenAnswers[answer.id]}
            totalChosenProb={chosenTotal}
            onChoose={onChoose}
            onDeselect={onDeselect}
          />
        ))}

      {!resolveOption && (
        <Col
          className={clsx(
            'gap-2 pr-2 md:pr-0',
            tradingAllowed(contract) ? '' : '-mb-6'
          )}
        >
          {answerItems.map((item) => (
            <OpenAnswer
              key={item.id}
              answer={item}
              contract={contract}
              colorIndex={colorSortedAnswer.indexOf(item.text)}
              onAnswerCommentClick={onAnswerCommentClick}
            />
          ))}
          {hasZeroBetAnswers && !showAllAnswers && (
            <Button
              className="self-end"
              color="gray-white"
              onClick={() => setShowAllAnswers(true)}
              size="md"
            >
              Show More
            </Button>
          )}
        </Col>
      )}

      {answers.length <= 1 && (
        <div className="pb-4 text-gray-500">No answers yet...</div>
      )}

      {outcomeType === 'FREE_RESPONSE' && tradingAllowed(contract) && (
        <CreateAnswerPanel contract={contract} />
      )}

      {(user?.id === creatorId || (isAdmin && needsAdminToResolve(contract))) &&
        !resolution && (
          <>
            <Spacer h={2} />
            <AnswerResolvePanel
              isAdmin={isAdmin}
              isCreator={user?.id === creatorId}
              contract={contract}
              resolveOption={resolveOption}
              setResolveOption={setResolveOption}
              chosenAnswers={chosenAnswers}
            />
          </>
        )}
    </Col>
  )
}

function OpenAnswer(props: {
  contract: FreeResponseContract | MultipleChoiceContract
  answer: Answer
  colorIndex: number | undefined
  onAnswerCommentClick: (answer: Answer) => void
}) {
  const { answer, contract, colorIndex, onAnswerCommentClick } = props
  const { username, avatarUrl, text } = answer
  const prob = getDpmOutcomeProbability(contract.totalShares, answer.id)
  const probPercent = formatPercent(prob)
  const [open, setOpen] = useState(false)
  const color =
    colorIndex != undefined && colorIndex < CHOICE_ANSWER_COLORS.length
      ? CHOICE_ANSWER_COLORS[colorIndex] + '55' // semi-transparent
      : '#B1B1C755'
  const colorWidth = 100 * Math.max(prob, 0.01)

  return (
    <Col className="my-1 px-2">
      <Modal open={open} setOpen={setOpen} position="center">
        <AnswerBetPanel
          answer={answer}
          contract={contract}
          closePanel={() => setOpen(false)}
          className="sm:max-w-84 !rounded-md bg-white !px-8 !py-6"
          isModal={true}
        />
      </Modal>

      <Col
        className={clsx(
          'relative w-full rounded-lg transition-all',
          tradingAllowed(contract) ? 'text-greyscale-7' : 'text-greyscale-5'
        )}
        style={{
          background: `linear-gradient(to right, ${color} ${colorWidth}%, #FBFBFF ${colorWidth}%)`,
        }}
      >
        <Row className="z-20 -mb-1 justify-between gap-2 py-2 px-3">
          <Row>
            <Avatar
              className="mt-0.5 mr-2 inline h-5 w-5 border border-transparent transition-transform hover:border-none"
              username={username}
              avatarUrl={avatarUrl}
            />
            <Linkify className="text-md whitespace-pre-line" text={text} />
          </Row>
          <Row className="gap-2">
            <div className="my-auto text-xl">{probPercent}</div>
            {tradingAllowed(contract) && (
              <Button
                size="2xs"
                color="gray-outline"
                onClick={() => setOpen(true)}
                className="my-auto"
              >
                BUY
              </Button>
            )}
            {
              <button
                className="p-1"
                onClick={() => onAnswerCommentClick(answer)}
              >
                <ChatIcon className="text-greyscale-4 hover:text-greyscale-6 h-5 w-5 transition-colors" />
              </button>
            }
          </Row>
        </Row>
      </Col>
    </Col>
  )
}