import React, { useState, useEffect, useContext, useRef, useMemo, useCallback } from "react";
import equal from "fast-deep-equal";

import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";

import "./Winner.css";

import { Resource } from "./Resource";
import { PlayerColor } from "./PlayerColor";
import { GlobalContext } from "./GlobalContext";

interface WinnerProps {
  winnerDismissed: boolean;
  setWinnerDismissed: (dismissed: boolean) => void;
}

/* eslint-disable @typescript-eslint/no-explicit-any */
const Winner: React.FC<WinnerProps> = ({ winnerDismissed, setWinnerDismissed }) => {
  const { ws, sendJsonMessage } = useContext(GlobalContext);
  const [winner, setWinner] = useState<any>(undefined);
  const [state, setState] = useState<string | undefined>(undefined);
  const fields = useMemo(() => ["winner", "state"], []);
  const onWsMessage = (event: MessageEvent) => {
    const data: { type: string; update: any } = JSON.parse(event.data);
    switch (data.type) {
      case "game-update":
        console.log(`winner - game update`, data.update);
        if ("winner" in data.update && !equal(data.update.winner, winner)) {
          setWinner(data.update.winner);
        }
        if ("state" in data.update && data.update.state !== state) {
          if (data.update.state !== "winner") {
            setWinner(undefined);
          }
          setWinnerDismissed(false);
          setState(data.update.state);
        }
        break;
      default:
        break;
    }
  };
  const refWsMessage = useRef(onWsMessage);
  useEffect(() => {
    refWsMessage.current = onWsMessage;
  });
  useEffect(() => {
    if (!ws) {
      return;
    }
    const cbMessage = (e: MessageEvent) => refWsMessage.current(e);
    ws.addEventListener("message", cbMessage);
    return () => {
      ws.removeEventListener("message", cbMessage);
    };
  }, [ws, refWsMessage]);
  useEffect(() => {
    if (!sendJsonMessage) {
      return;
    }
    sendJsonMessage({
      type: "get",
      fields,
    });
  }, [sendJsonMessage, fields]);

  const quitClicked = useCallback(() => {
    if (!winnerDismissed) {
      setWinnerDismissed(true);
      sendJsonMessage({
        type: "goto-lobby",
      });
    }
  }, [sendJsonMessage, winnerDismissed, setWinnerDismissed]);

  if (!winner || winnerDismissed) {
    return <></>;
  }

  let losers = [];
  for (const key in winner.players) {
    if (key === winner.color || winner.players[key].status === "Not active") {
      continue;
    }
    losers.push(winner.players[key]);
  }

  const turnCount = Math.floor(winner.turns / (losers.length + 1));

  losers = losers.map((player: any) => {
    const averageSeconds = Math.floor(player.totalTime / turnCount / 1000),
      average = `${Math.floor(averageSeconds / 60)}m:${averageSeconds % 60}s`;
    return (
      <div key={player.color}>
        <PlayerColor color={player.color} /> {player.name} finished with {player.points} victory points.
        {Number(player.potential) !== 0 && (
          <>
            They had <b>{player.potential}</b> unplayed Victory Point card(s).
          </>
        )}
        Their average turn time was {average}.
      </div>
    );
  });

  let robber;
  let max = 0;

  let playerStolen: any = {};
  const stats = winner.stolen;
  for (const player in stats) {
    if (player === "total" || player === "player") {
      continue;
    }
    if (player === "robber") {
      robber = <></>;
      for (const type in stats.robber.stole) {
        if (type === "total") {
          continue;
        }
        const count = stats.robber.stole[type];
        robber = (
          <>
            {robber}
            <Resource label={true} type={type} count={count} disabled />
          </>
        );
      }
      robber = (
        <div>
          Throughout the game, the robber blocked <b>{stats.robber.stole.total}</b> resources:
          <div className="ThiefStole">{robber}</div>
        </div>
      );
      continue;
    }

    if (stats[player].stolen.total < max) {
      continue;
    }
    if (stats[player].stolen.total > max) {
      max = stats[player].stolen.total;
      playerStolen = {
        robber: stats[player].stolen.robber,
        player: stats[player].stolen.player,
        element: <></>,
      };
    }

    let stolen;
    for (const type in stats[player].stolen) {
      if (["total", "robber", "player"].indexOf(type) !== -1) {
        continue;
      }
      if (!stolen) {
        stolen = <></>;
      }
      const count = stats[player].stolen[type];
      stolen = (
        <>
          {stolen}
          <Resource label={true} type={type} count={count} disabled />
        </>
      );
    }
    if (stolen) {
      playerStolen.element = (
        <div key={player}>
          <PlayerColor color={player} /> {winner.players[player].name}
          <div className="PlayerStolen">{stolen}</div>
        </div>
      );
    }
  }

  if (!robber) {
    robber = <div>The robber never blocked any resources from anyone!</div>;
  }

  const averageSeconds = Math.floor(winner.totalTime / turnCount / 1000),
    average = `${Math.floor(averageSeconds / 60)}m:${averageSeconds % 60}s`;

  const seconds = winner.elapsedTime / 1000,
    h = Math.floor(seconds / (60 * 60)),
    m = Math.floor((seconds % (60 * 60)) / 60),
    s = Math.floor((seconds % (60 * 60)) % 60);
  const totalTime = `${h}h:${m}m:${s}s`;

  const vpType: string[] = ["market", "university", "library", "palace"];
  const selectedVpType = vpType[Math.floor(vpType.length * Math.random())];

  return (
    <div className="Winner">
      <Paper>
        <div className="Title">
          {winner.name} has won with {winner.points} victory points!
        </div>
        <div style={{ display: "flex", flexDirection: "row" }}>
          <Resource type={`vp-${selectedVpType}`} disabled count={1} />
          <div className="Description">
            <div>
              Congratulations, <b>{winner.name}</b>!
            </div>
            <div>
              <PlayerColor color={winner.color} /> {winner.name} won the game with <b>{winner.points}</b> Victory Points
              after {turnCount} game turns.
              {Number(winner.potential) !== 0 && (
                <>
                  They had <b>{winner.potential}</b> unplayed Victory Point card(s).
                </>
              )}
              Their average turn time was {average}.
            </div>
            {losers}
            <div>The game took {totalTime}.</div>
            {robber}
            {max !== 0 && (
              <>
                <div>
                  The robber stole {playerStolen.robber} and other players stole {playerStolen.player} resources from:
                </div>
                <div className="PlayerStolenList">{playerStolen.element}</div>
              </>
            )}
          </div>
        </div>
        <Button onClick={quitClicked}>Go back to Lobby</Button>
      </Paper>
    </div>
  );
};

export { Winner };
