import React, { useEffect, useState } from 'react'
import Confetti from 'react-confetti'

import { fromPropz, usePropz } from 'web/hooks/use-propz'
import { contractPath, getContractFromSlug } from 'web/lib/firebase/contracts'
import { useContractWithPreload } from 'web/hooks/use-contract'
import { DOMAIN } from 'common/envs/constants'
import { Col } from 'web/components/layout/col'
import { SiteLink } from 'web/components/site-link'
import { Spacer } from 'web/components/layout/spacer'
import { Row } from 'web/components/layout/row'
import { Challenge } from 'common/challenge'
import {
  getChallenge,
  getChallengeUrl,
  useChallenge,
} from 'web/lib/firebase/challenges'
import { getUserByUsername } from 'web/lib/firebase/users'
import { User } from 'common/user'
import { Page } from 'web/components/page'
import { useUser, useUserById } from 'web/hooks/use-user'
import { AcceptChallengeButton } from 'web/components/challenges/accept-challenge-button'
import { Avatar } from 'web/components/avatar'
import { BinaryOutcomeLabel } from 'web/components/outcome-label'
import { formatMoney } from 'common/util/format'
import { LoadingIndicator } from 'web/components/loading-indicator'
import { useWindowSize } from 'web/hooks/use-window-size'
import { Bet, listAllBets } from 'web/lib/firebase/bets'
import { SEO } from 'web/components/SEO'
import Custom404 from 'web/pages/404'
import { useSaveReferral } from 'web/hooks/use-save-referral'
import { BinaryContract } from 'common/contract'
import { Title } from 'web/components/title'
import { getOpenGraphProps } from 'common/contract-details'
import { UserLink } from 'web/components/user-link'

export const getStaticProps = fromPropz(getStaticPropz)

export async function getStaticPropz(props: {
  params: { username: string; contractSlug: string; challengeSlug: string }
}) {
  const { username, contractSlug, challengeSlug } = props.params
  const contract = (await getContractFromSlug(contractSlug)) || null
  const user = (await getUserByUsername(username)) || null
  const bets = contract?.id ? await listAllBets(contract.id) : []
  const challenge = contract?.id
    ? await getChallenge(challengeSlug, contract.id)
    : null

  return {
    props: {
      contract,
      user,
      slug: contractSlug,
      challengeSlug,
      bets,
      challenge,
    },

    revalidate: 60, // regenerate after a minute
  }
}

export async function getStaticPaths() {
  return { paths: [], fallback: 'blocking' }
}

export default function ChallengePage(props: {
  contract: BinaryContract | null
  user: User
  slug: string
  bets: Bet[]
  challenge: Challenge | null
  challengeSlug: string
}) {
  props = usePropz(props, getStaticPropz) ?? {
    contract: null,
    user: null,
    challengeSlug: '',
    bets: [],
    challenge: null,
    slug: '',
  }
  const contract = (useContractWithPreload(props.contract) ??
    props.contract) as BinaryContract

  const challenge =
    useChallenge(props.challengeSlug, contract?.id) ?? props.challenge

  const { user, bets } = props
  const currentUser = useUser()

  useSaveReferral(currentUser, {
    defaultReferrerUsername: challenge?.creatorUsername,
    contractId: challenge?.contractId,
  })

  if (!contract || !challenge) return <Custom404 />

  const ogCardProps = getOpenGraphProps(contract)
  ogCardProps.creatorUsername = challenge.creatorUsername
  ogCardProps.creatorName = challenge.creatorName
  ogCardProps.creatorAvatarUrl = challenge.creatorAvatarUrl

  return (
    <Page>
      <SEO
        title={ogCardProps.question}
        description={ogCardProps.description}
        url={getChallengeUrl(challenge).replace('https://', '')}
        ogCardProps={ogCardProps}
        challenge={challenge}
      />
      {challenge.acceptances.length >= challenge.maxUses ? (
        <ClosedChallengeContent
          contract={contract}
          challenge={challenge}
          creator={user}
        />
      ) : (
        <OpenChallengeContent
          user={currentUser}
          contract={contract}
          challenge={challenge}
          creator={user}
          bets={bets}
        />
      )}

      <FAQ />
    </Page>
  )
}

function FAQ() {
  const [toggleWhatIsThis, setToggleWhatIsThis] = useState(false)
  const [toggleWhatIsMana, setToggleWhatIsMana] = useState(false)
  return (
    <Col className={'items-center gap-4 p-2 md:p-6 lg:items-start'}>
      <Row className={'text-xl text-indigo-700'}>FAQ</Row>
      <Row className={'text-lg text-indigo-700'}>
        <span
          className={'mx-2 cursor-pointer'}
          onClick={() => setToggleWhatIsThis(!toggleWhatIsThis)}
        >
          {toggleWhatIsThis ? '-' : '+'}
          What is this?
        </span>
      </Row>
      {toggleWhatIsThis && (
        <Row className={'mx-4'}>
          <span>
            This is a challenge bet, or a bet offered from one person to another
            that is only realized if both parties agree. You can agree to the
            challenge (if it's open) or create your own from a market page. See
            more markets{' '}
            <SiteLink className={'font-bold'} href={'/home'}>
              here.
            </SiteLink>
          </span>
        </Row>
      )}
      <Row className={'text-lg text-indigo-700'}>
        <span
          className={'mx-2 cursor-pointer'}
          onClick={() => setToggleWhatIsMana(!toggleWhatIsMana)}
        >
          {toggleWhatIsMana ? '-' : '+'}
          What is M$?
        </span>
      </Row>
      {toggleWhatIsMana && (
        <Row className={'mx-4'}>
          Mana (M$) is the play-money used by our platform to keep track of your
          bets. It's completely free to get started, and you can donate your
          winnings to charity!
        </Row>
      )}
    </Col>
  )
}

function ClosedChallengeContent(props: {
  contract: BinaryContract
  challenge: Challenge
  creator: User
}) {
  const { contract, challenge, creator } = props
  const { resolution, question } = contract
  const {
    acceptances,
    creatorAmount,
    creatorOutcome,
    acceptorOutcome,
    acceptorAmount,
  } = challenge

  const user = useUserById(acceptances[0].userId)

  const [showConfetti, setShowConfetti] = useState(false)
  const { width, height } = useWindowSize()
  useEffect(() => {
    if (acceptances.length === 0) return
    if (acceptances[0].createdTime > Date.now() - 1000 * 60)
      setShowConfetti(true)
  }, [acceptances])

  const creatorWon = resolution === creatorOutcome

  const href = `https://${DOMAIN}${contractPath(contract)}`

  if (!user) return <LoadingIndicator />

  const winner = (creatorWon ? creator : user).name

  return (
    <>
      {showConfetti && (
        <Confetti
          width={width ?? 500}
          height={height ?? 500}
          confettiSource={{
            x: ((width ?? 500) - 200) / 2,
            y: 0,
            w: 200,
            h: 0,
          }}
          recycle={false}
          initialVelocityY={{ min: 1, max: 3 }}
          numberOfPieces={200}
        />
      )}
      <Col className=" w-full items-center justify-center rounded border-0 border-gray-100 bg-white py-6 pl-1 pr-2 sm:px-2 md:px-6 md:py-8 ">
        {resolution ? (
          <>
            <Title className="!mt-0" text={`🥇 ${winner} wins the bet 🥇`} />
            <SiteLink href={href} className={'mb-8 text-xl'}>
              {question}
            </SiteLink>
          </>
        ) : (
          <SiteLink href={href} className={'mb-8'}>
            <span className="text-3xl text-indigo-700">{question}</span>
          </SiteLink>
        )}
        <Col
          className={'w-full content-between justify-between gap-1 sm:flex-row'}
        >
          <UserBetColumn
            challenger={creator}
            outcome={creatorOutcome}
            amount={creatorAmount}
            isResolved={!!resolution}
          />

          <Col className="items-center justify-center py-8 text-2xl sm:text-4xl">
            VS
          </Col>

          <UserBetColumn
            challenger={user?.id === creator.id ? undefined : user}
            outcome={acceptorOutcome}
            amount={acceptorAmount}
            isResolved={!!resolution}
          />
        </Col>
        <Spacer h={3} />

        {/* <Row className="mt-8 items-center">
          <span className='mr-4'>Share</span> <CopyLinkButton url={window.location.href} />
        </Row> */}
      </Col>
    </>
  )
}

function OpenChallengeContent(props: {
  contract: BinaryContract
  challenge: Challenge
  creator: User
  user: User | null | undefined
  bets: Bet[]
}) {
  const { contract, challenge, creator, user } = props
  const { question } = contract
  const {
    creatorAmount,
    creatorId,
    creatorOutcome,
    acceptorAmount,
    acceptorOutcome,
  } = challenge

  const href = `https://${DOMAIN}${contractPath(contract)}`

  return (
    <Col className="items-center">
      <Col className="h-full items-center justify-center rounded bg-white p-4 py-8 sm:p-8 sm:shadow-md">
        <SiteLink href={href} className={'mb-8'}>
          <span className="text-3xl text-indigo-700">{question}</span>
        </SiteLink>

        <Col
          className={
            ' w-full content-between justify-between gap-1 sm:flex-row'
          }
        >
          <UserBetColumn
            challenger={creator}
            outcome={creatorOutcome}
            amount={creatorAmount}
          />

          <Col className="items-center justify-center py-4 text-2xl sm:py-8 sm:text-4xl">
            VS
          </Col>

          <UserBetColumn
            challenger={user?.id === creatorId ? undefined : user}
            outcome={acceptorOutcome}
            amount={acceptorAmount}
          />
        </Col>

        <Spacer h={3} />
        <Row className={'my-4 text-center text-gray-500'}>
          <span>
            {`${creator.name} will bet ${formatMoney(
              creatorAmount
            )} on ${creatorOutcome} if you bet ${formatMoney(
              acceptorAmount
            )} on ${acceptorOutcome}. Whoever is right will get `}
            <span className="mr-1 font-bold ">
              {formatMoney(creatorAmount + acceptorAmount)}
            </span>
            total.
          </span>
        </Row>

        <Row className="my-4 w-full items-center justify-center">
          <AcceptChallengeButton
            user={user}
            contract={contract}
            challenge={challenge}
          />
        </Row>
      </Col>
    </Col>
  )
}

const userCol = (challenger: User) => (
  <Col className={'mb-2 w-full items-center justify-center gap-2'}>
    <UserLink
      className={'text-2xl'}
      name={challenger.name}
      username={challenger.username}
    />
    <Avatar
      size={24}
      avatarUrl={challenger.avatarUrl}
      username={challenger.username}
    />
  </Col>
)

function UserBetColumn(props: {
  challenger: User | null | undefined
  outcome: string
  amount: number
  isResolved?: boolean
}) {
  const { challenger, outcome, amount, isResolved } = props

  return (
    <Col className="w-full items-start justify-center gap-1">
      {challenger ? (
        userCol(challenger)
      ) : (
        <Col className={'mb-2 w-full items-center justify-center gap-2'}>
          <span className={'text-2xl'}>You</span>
          <Avatar
            className={'h-[7.25rem] w-[7.25rem]'}
            avatarUrl={undefined}
            username={undefined}
          />
        </Col>
      )}
      <Row className={'w-full items-center justify-center'}>
        <span className={'text-lg'}>
          {isResolved ? 'had bet' : challenger ? '' : ''}
        </span>
      </Row>
      <Row className={'w-full items-center justify-center'}>
        <span className={'text-lg'}>
          <span className="bold text-2xl">{formatMoney(amount)}</span>
          {' on '}
          <span className="bold text-2xl">
            <BinaryOutcomeLabel outcome={outcome as any} />
          </span>{' '}
        </span>
      </Row>
    </Col>
  )
}