import React, { useMemo, useState } from 'react'
import { DatumValue } from '@nivo/core'
import { ResponsiveLine } from '@nivo/line'

import { Entry, makeEntries } from 'web/lib/simulator/entries'
import { Col } from 'web/components/layout/col'

function TableBody(props: { entries: Entry[] }) {
  return (
    <tbody>
      {props.entries.map((entry, i) => (
        <tr key={i}>
          <th>{props.entries.length - i}</th>
          <TableRowStart entry={entry} />
          <TableRowEnd entry={entry} />
        </tr>
      ))}
    </tbody>
  )
}

function TableRowStart(props: { entry: Entry }) {
  const { entry } = props
  if (entry.yesBid && entry.noBid) {
    return (
      <>
        <td>
          <div className="badge">ANTE</div>
        </td>
        <td>
          ${entry.yesBid} / ${entry.noBid}
        </td>
      </>
    )
  } else if (entry.yesBid) {
    return (
      <>
        <td>
          <div className="badge badge-success">YES</div>
        </td>
        <td>${entry.yesBid}</td>
      </>
    )
  } else {
    return (
      <>
        <td>
          <div className="badge badge-error">NO</div>
        </td>
        <td>${entry.noBid}</td>
      </>
    )
  }
}

function TableRowEnd(props: { entry: Entry | null; isNew?: boolean }) {
  const { entry } = props
  if (!entry) {
    return (
      <>
        <td>0</td>
        <td>0</td>
        {!props.isNew && (
          <>
            <td>N/A</td>
            <td>N/A</td>
          </>
        )}
      </>
    )
  } else if (entry.yesBid && entry.noBid) {
    return (
      <>
        <td>{(entry.prob * 100).toFixed(1)}%</td>
        <td>N/A</td>
        {!props.isNew && (
          <>
            <td>N/A</td>
            <td>N/A</td>
          </>
        )}
      </>
    )
  } else if (entry.yesBid) {
    return (
      <>
        <td>{(entry.prob * 100).toFixed(1)}%</td>
        <td>${entry.yesWeight.toFixed(0)}</td>
        {!props.isNew && (
          <>
            <td>${entry.yesPayout.toFixed(0)}</td>
            <td>{(entry.yesReturn * 100).toFixed(0)}%</td>
          </>
        )}
      </>
    )
  } else {
    return (
      <>
        <td>{(entry.prob * 100).toFixed(1)}%</td>
        <td>${entry.noWeight.toFixed(0)}</td>
        {!props.isNew && (
          <>
            <td>${entry.noPayout.toFixed(0)}</td>
            <td>{(entry.noReturn * 100).toFixed(0)}%</td>
          </>
        )}
      </>
    )
  }
}

type Bid = { yesBid: number; noBid: number }

function NewBidTable(props: {
  steps: number
  bids: Array<Bid>
  setSteps: (steps: number) => void
  setBids: (bids: Array<Bid>) => void
}) {
  const { steps, bids, setSteps, setBids } = props
  // Prepare for new bids
  const [newBid, setNewBid] = useState(0)
  const [newBidType, setNewBidType] = useState('YES')

  function makeBid(type: string, bid: number) {
    return {
      yesBid: type == 'YES' ? bid : 0,
      noBid: type == 'YES' ? 0 : bid,
    }
  }

  function submitBid() {
    if (newBid <= 0) return
    const bid = makeBid(newBidType, newBid)
    bids.splice(steps, 0, bid)
    setBids(bids)
    setSteps(steps + 1)
    setNewBid(0)
  }

  function toggleBidType() {
    setNewBidType(newBidType === 'YES' ? 'NO' : 'YES')
  }

  const nextBid = makeBid(newBidType, newBid)
  const fakeBids = [...bids.slice(0, steps), nextBid]
  const entries = makeEntries(fakeBids)
  const nextEntry = entries[entries.length - 1]

  function randomBid() {
    const bidType = Math.random() < 0.5 ? 'YES' : 'NO'
    // const p = bidType === 'YES' ? nextEntry.prob : 1 - nextEntry.prob

    const amount = Math.floor(Math.random() * 300) + 1
    const bid = makeBid(bidType, amount)

    bids.splice(steps, 0, bid)
    setBids(bids)
    setSteps(steps + 1)
    setNewBid(0)
  }

  return (
    <>
      <table className="table-compact my-8 table w-full text-center">
        <thead>
          <tr>
            <th>Order #</th>
            <th>Type</th>
            <th>Bet</th>
            <th>Prob</th>
            <th>Est Payout</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <th>{steps + 1}</th>
            <td>
              <div
                className={
                  `badge hover:cursor-pointer ` +
                  (newBidType == 'YES' ? 'badge-success' : 'badge-ghost')
                }
                onClick={toggleBidType}
              >
                YES
              </div>
              <br />
              <div
                className={
                  `badge hover:cursor-pointer ` +
                  (newBidType == 'NO' ? 'badge-error' : 'badge-ghost')
                }
                onClick={toggleBidType}
              >
                NO
              </div>
            </td>
            <td>
              {/* Note: Would love to make this input smaller... */}
              <input
                type="number"
                placeholder="0"
                className="input input-bordered"
                style={{ maxWidth: 100 }}
                value={newBid.toString()}
                onChange={(e) => setNewBid(parseInt(e.target.value) || 0)}
                onKeyUp={(e) => {
                  if (e.key === 'Enter') {
                    submitBid()
                  }
                }}
                onFocus={(e) => e.target.select()}
              />
            </td>

            <TableRowEnd entry={nextEntry} isNew />

            <button
              className="btn btn-primary mt-2"
              onClick={() => submitBid()}
              disabled={newBid <= 0}
            >
              Submit
            </button>
          </tr>
        </tbody>
      </table>

      <button className="btn btn-secondary mb-4" onClick={randomBid}>
        Random bet!
      </button>
    </>
  )
}

// Show a hello world React page
export default function Simulator() {
  const [steps, setSteps] = useState(1)
  const [bids, setBids] = useState([{ yesBid: 100, noBid: 100 }])

  const entries = useMemo(
    () => makeEntries(bids.slice(0, steps)),
    [bids, steps]
  )

  const reversedEntries = [...entries].reverse()

  const probs = entries.map((entry) => entry.prob)
  const points = probs.map((prob, i) => ({ x: i + 1, y: prob * 100 }))
  const data = [{ id: 'Yes', data: points, color: '#11b981' }]
  const tickValues = [0, 25, 50, 75, 100]

  return (
    <Col>
      <div className="mx-auto mt-8 grid w-full grid-cols-1 gap-4 p-2 text-center xl:grid-cols-2">
        {/* Left column */}
        <div>
          <h1 className="mb-8 text-2xl font-bold">
            Dynamic Parimutuel Market Simulator
          </h1>

          <NewBidTable {...{ steps, bids, setSteps, setBids }} />

          {/* History of bids */}
          <div className="overflow-x-auto">
            <table className="table w-full text-center">
              <thead>
                <tr>
                  <th>Order #</th>
                  <th>Type</th>
                  <th>Bet</th>
                  <th>Prob</th>
                  <th>Est Payout</th>
                  <th>Payout</th>
                  <th>Return</th>
                </tr>
              </thead>

              <TableBody entries={reversedEntries} />
            </table>
          </div>
        </div>

        {/* Right column */}
        <Col>
          <h1 className="mb-8 text-2xl font-bold">
            Probability of
            <div className="badge badge-success w-18 ml-3 h-8 text-2xl">
              YES
            </div>
          </h1>
          <div className="mb-10 w-full" style={{ height: 500 }}>
            <ResponsiveLine
              data={data}
              yScale={{ min: 0, max: 100, type: 'linear' }}
              yFormat={formatPercent}
              gridYValues={tickValues}
              axisLeft={{
                tickValues,
                format: formatPercent,
              }}
              enableGridX={false}
              colors={{ datum: 'color' }}
              pointSize={8}
              pointBorderWidth={1}
              pointBorderColor="#fff"
              enableSlices="x"
              enableArea
              margin={{ top: 20, right: 10, bottom: 20, left: 40 }}
            />
          </div>
          {/* Range slider that sets the current step */}
          <label>Orders # 1 - {steps}</label>
          <input
            type="range"
            className="range"
            min="1"
            max={bids.length}
            value={steps}
            onChange={(e) => setSteps(parseInt(e.target.value))}
          />
        </Col>
      </div>
    </Col>
  )
}

function formatPercent(y: DatumValue) {
  return `${Math.round(+y.toString())}%`
}
