import React, { useEffect, useState } from "react";

import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";
import { Player } from "@player";
import { Money } from "../ui/React/Money";
import { BetInput } from "./BetInput";
import { hasEnoughMoney, reachedLimit, win } from "./Game";
import { WHRNG } from "./RNG";
import { trusted } from "./utils";

// statically shuffled array of symbols.
const symbols = [
  "D",
  "C",
  "$",
  "?",
  "♥",
  "A",
  "C",
  "B",
  "C",
  "E",
  "B",
  "E",
  "C",
  "*",
  "D",
  "♥",
  "B",
  "A",
  "A",
  "A",
  "C",
  "A",
  "D",
  "B",
  "E",
  "?",
  "D",
  "*",
  "@",
  "♥",
  "B",
  "E",
  "?",
];

function getPayout(s: string, n: number): number {
  switch (s) {
    case "$":
      return [20, 200, 1000][n];
    case "@":
      return [8, 80, 400][n];
    case "♥":
    case "?":
      return [6, 20, 150][n];
    case "D":
    case "E":
      return [1, 8, 30][n];
    default:
      return [1, 5, 20][n];
  }
}

const payLines = [
  // lines
  [
    [0, 0],
    [0, 1],
    [0, 2],
    [0, 3],
    [0, 4],
  ],
  [
    [1, 0],
    [1, 1],
    [1, 2],
    [1, 3],
    [1, 4],
  ],
  [
    [2, 0],
    [2, 1],
    [2, 2],
    [2, 3],
    [2, 4],
  ],

  // Vs
  [
    [2, 0],
    [1, 1],
    [0, 2],
    [1, 3],
    [2, 4],
  ],
  [
    [0, 0],
    [1, 1],
    [2, 2],
    [1, 3],
    [0, 4],
  ],

  // rest
  [
    [0, 0],
    [1, 1],
    [1, 2],
    [1, 3],
    [0, 4],
  ],
  [
    [2, 0],
    [1, 1],
    [1, 2],
    [1, 3],
    [2, 4],
  ],
  [
    [1, 0],
    [0, 1],
    [0, 2],
    [0, 3],
    [1, 4],
  ],
  [
    [1, 0],
    [2, 1],
    [2, 2],
    [2, 3],
    [1, 4],
  ],
];

const initialBet = 1000;
const maxBet = 1e6;

export function SlotMachine(): React.ReactElement {
  const [rng] = useState(new WHRNG(Player.totalPlaytime));
  const [index, setIndex] = useState<number[]>([0, 0, 0, 0, 0]);
  const [locks, setLocks] = useState<number[]>([0, 0, 0, 0, 0]);
  const [investment, setInvestment] = useState(initialBet);
  const [canPlay, setCanPlay] = useState(true);
  const [status, setStatus] = useState<string | JSX.Element>("waiting");

  useEffect(() => {
    const i = window.setInterval(step, 50);
    return () => clearInterval(i);
  });

  function step(): void {
    let stoppedOne = false;
    const copy = index.slice();
    for (let i = 0; i < copy.length; i++) {
      if (copy[i] === locks[i] && !stoppedOne) continue;
      copy[i] = copy[i] - 1 >= 0 ? copy[i] - 1 : symbols.length - 1;
      stoppedOne = true;
    }

    setIndex(copy);

    if (stoppedOne && copy.every((e, i) => e === locks[i])) {
      checkWinnings(getTable(copy, symbols));
    }
  }

  function getTable(index: number[], symbols: string[]): string[][] {
    return [
      [
        symbols[(index[0] + symbols.length - 1) % symbols.length],
        symbols[(index[1] + symbols.length - 1) % symbols.length],
        symbols[(index[2] + symbols.length - 1) % symbols.length],
        symbols[(index[3] + symbols.length - 1) % symbols.length],
        symbols[(index[4] + symbols.length - 1) % symbols.length],
      ],
      [symbols[index[0]], symbols[index[1]], symbols[index[2]], symbols[index[3]], symbols[index[4]]],
      [
        symbols[(index[0] + 1) % symbols.length],
        symbols[(index[1] + 1) % symbols.length],
        symbols[(index[2] + 1) % symbols.length],
        symbols[(index[3] + 1) % symbols.length],
        symbols[(index[4] + 1) % symbols.length],
      ],
    ];
  }

  function play(): void {
    if (reachedLimit() || !hasEnoughMoney(investment)) {
      return;
    }
    setStatus("playing");
    win(-investment);
    if (!canPlay) return;
    unlock();
    setTimeout(lock, rng.random() * 2000 + 1000);
  }

  function lock(): void {
    setLocks([
      Math.floor(rng.random() * symbols.length),
      Math.floor(rng.random() * symbols.length),
      Math.floor(rng.random() * symbols.length),
      Math.floor(rng.random() * symbols.length),
      Math.floor(rng.random() * symbols.length),
    ]);
  }

  function checkWinnings(t: string[][]): void {
    const getPaylineData = function (payline: number[][]): string[] {
      const data = [];
      for (const point of payline) {
        data.push(t[point[0]][point[1]]);
      }
      return data;
    };

    const countSequence = function (data: string[]): number {
      let count = 1;
      for (let i = 1; i < data.length; i++) {
        if (data[i] !== data[i - 1]) break;
        count++;
      }

      return count;
    };

    let gains = -investment;
    for (const payline of payLines) {
      const data = getPaylineData(payline);
      const count = countSequence(data);
      if (count < 3) continue;
      const payout = getPayout(data[0], count - 3);
      gains += investment * payout;
      win(investment * payout);
    }

    setStatus(
      <>
        {gains > 0 ? "gained" : "lost"} <Money money={Math.abs(gains)} />
      </>,
    );
    setCanPlay(true);
  }

  function unlock(): void {
    setLocks([-1, -1, -1, -1, -1]);
    setCanPlay(false);
  }

  const t = getTable(index, symbols);
  // prettier-ignore
  return (
      <>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>+———————————————————————+</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>| | {t[0][0]} | {t[0][1]} | {t[0][2]} | {t[0][3]} | {t[0][4]} | |</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>| |   |   |   |   |   | |</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>| | {symbols[index[0]]} | {symbols[index[1]]} | {symbols[index[2]]} | {symbols[index[3]]} | {symbols[index[4]]} | |</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>| |   |   |   |   |   | |</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>| | {symbols[(index[0]+1)%symbols.length]} | {symbols[(index[1]+1)%symbols.length]} | {symbols[(index[2]+1)%symbols.length]} | {symbols[(index[3]+1)%symbols.length]} | {symbols[(index[4]+1)%symbols.length]} | |</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>+———————————————————————+</Typography>
        <BetInput
          initialBet={initialBet}
          maxBet={maxBet}
          gameInProgress={!canPlay}
          setBet={(bet) => {
            setInvestment(bet);
          }}
        />
        <div>
          <Button onClick={trusted(play)} disabled={!canPlay}>
            Spin!
          </Button>
        </div>

        <Typography variant="h4">{status}</Typography>
        <Typography>Pay lines</Typography>

<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>-----   ·····   ·····</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>·····   -----   ·····</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>·····   ·····   -----</Typography>
<br />

<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>··^··   \···/   \···/</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>·/·\·   ·\·/·   ·---·</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>/···\   ··v··   ·····</Typography>
<br />

<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>·····   ·---·   ·····</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>·---·   /···\   \···/</Typography>
<Typography sx={{ lineHeight: "1em", whiteSpace: "pre" }}>/···\   ·····   ·---·</Typography>
        </>
    );
}

// https://felgo.com/doc/how-to-make-a-slot-game-tutorial/
