import React, { useState, useEffect, useContext, useRef, useMemo, useCallback } from "react";
import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";
import equal from "fast-deep-equal";

import "./Actions.css";
import { PlayerName } from "./PlayerName";
import { GlobalContext } from "./GlobalContext";

type PrivateData = {
  orderRoll?: boolean;
  resources?: number;
  mustDiscard?: number;
};

type TurnData = {
  roll?: number;
  color?: string;
  active?: string;
  actions?: string[];
  select?: unknown;
  robberInAction?: boolean;
};

type PlayerData = {
  live?: boolean;
};

type ActionsProps = {
  tradeActive: boolean;
  setTradeActive: (b: boolean) => void;
  buildActive: boolean;
  setBuildActive: (b: boolean) => void;
  houseRulesActive: boolean;
  setHouseRulesActive: (b: boolean) => void;
};

const Actions: React.FC<ActionsProps> = ({
  tradeActive,
  setTradeActive,
  buildActive,
  setBuildActive,
  houseRulesActive,
  setHouseRulesActive,
}) => {
  const { lastJsonMessage, sendJsonMessage, name, roomName } = useContext(GlobalContext);
  const [state, setState] = useState<string>("lobby");
  const [color, setColor] = useState<string | undefined>(undefined);
  const [priv, setPriv] = useState<PrivateData | undefined>(undefined);
  const [turn, setTurn] = useState<TurnData>({});
  const [edit, setEdit] = useState<string | undefined>(name);
  const [active, setActive] = useState<number>(0);
  const [players, setPlayers] = useState<Record<string, PlayerData>>({});
  const [alive, setAlive] = useState<number>(0);

  const fields = useMemo(() => ["state", "turn", "private", "active", "color", "players"], []);

  useEffect(() => {
    sendJsonMessage({ type: "get", fields });
  }, [sendJsonMessage, fields]);

  useEffect(() => {
    if (!lastJsonMessage) {
      return;
    }

    const data = lastJsonMessage;
    switch (data.type) {
      case "game-update":
        console.log(`actions - game update`, data.update);
        if ("private" in data.update && !equal(data.update.private, priv)) {
          setPriv(data.update.private);
        }
        if ("state" in data.update && data.update.state !== state) {
          setState(data.update.state);
        }
        if ("color" in data.update && data.update.color !== color) {
          setColor(data.update.color);
        }
        if ("name" in data.update && data.update.name !== edit) {
          setEdit(data.update.name);
          console.log("Actions: setEdit from data.update.name =", data.update.name);
        }
        if ("turn" in data.update && !equal(data.update.turn, turn)) {
          setTurn(data.update.turn);
        }
        if ("active" in data.update && data.update.active !== active) {
          setActive(data.update.active);
        }

        if ("players" in data.update && !equal(data.update.players, players)) {
          setPlayers(data.update.players);
        }
        break;
      default:
        break;
    }
  }, [lastJsonMessage, state, color, edit, turn, active, players, priv]);

  const buildClicked = () => {
    setBuildActive(!buildActive);
  };

  useEffect(() => {
    let count = 0;
    for (const key in players) {
      // players entries are dynamic; guard access
      const p = players[key];
      if (p && p.live) {
        count++;
      }
    }
    setAlive(count);
  }, [players, setAlive]);

  const setName = (update: string) => {
    if (update !== name) {
      sendJsonMessage({ type: "player-name", name: update });
    }
    setEdit(name);
    if (buildActive) setBuildActive(false);
  };

  const changeNameClick = () => {
    console.log("Actions: changeNameClick called, setting edit to ''");
    setEdit("");
    if (buildActive) setBuildActive(false);
  };

  const discardClick = () => {
    const nodes = document.querySelectorAll(".Hand .Resource.Selected");
    const discards: Record<string, number> = { wheat: 0, brick: 0, sheep: 0, stone: 0, wood: 0 };
    for (let i = 0; i < nodes.length; i++) {
      const t = nodes[i].getAttribute("data-type") || "";
      discards[t] = (discards[t] || 0) + 1;
      nodes[i].classList.remove("Selected");
    }
    sendJsonMessage({ type: "discard", discards });
    if (buildActive) setBuildActive(false);
  };

  const newTableClick = () => {
    sendJsonMessage({ type: "shuffle" });
    if (buildActive) setBuildActive(false);
  };

  const tradeClick = () => {
    if (!tradeActive) {
      setTradeActive(true);
      sendJsonMessage({ type: "trade" });
    } else {
      setTradeActive(false);
      sendJsonMessage({ type: "trade", action: "cancel", offer: undefined });
    }
    if (buildActive) setBuildActive(false);
  };

  const rollClick = () => {
    sendJsonMessage({ type: "roll" });
    if (buildActive) setBuildActive(false);
  };
  const passClick = () => {
    sendJsonMessage({ type: "pass" });
    if (buildActive) setBuildActive(false);
  };
  const houseRulesClick = () => {
    setHouseRulesActive(!houseRulesActive);
  };
  const startClick = () => {
    sendJsonMessage({ type: "set", field: "state", value: "game-order" });
    if (buildActive) setBuildActive(false);
  };
  const resetGame = () => {
    sendJsonMessage({ type: "clear-game" });
    if (buildActive) setBuildActive(false);
  };

  if (!roomName) {
    return <Paper className="Actions" />;
  }

  const inLobby = state === "lobby",
    inGame = state === "normal",
    inGameOrder = state === "game-order",
    hasGameOrderRolled = priv && priv.orderRoll ? true : false,
    hasRolled = turn && turn.roll ? true : false,
    isTurn = turn && turn.color === color ? true : false,
    robberActions = turn && turn.robberInAction,
    haveResources = priv ? priv.resources !== 0 : false,
    volcanoActive = state === "volcano",
    placement = state === "initial-placement" || (turn && turn.active === "road-building"),
    placeRoad =
      placement &&
      turn &&
      turn.actions &&
      (turn.actions.indexOf("place-road") !== -1 ||
        turn.actions.indexOf("place-city") !== -1 ||
        turn.actions.indexOf("place-settlement") !== -1);

  if (tradeActive && (!turn || !turn.actions || turn.actions.indexOf("trade"))) {
    setTradeActive(false);
  } else if (!tradeActive && turn && turn.actions && turn.actions.indexOf("trade") !== -1) {
    setTradeActive(true);
  }

  let disableRoll = false;
  if (robberActions) {
    disableRoll = true;
  }
  if (turn && turn.select) {
    disableRoll = true;
  }
  if (inGame && !isTurn) {
    disableRoll = true;
  }
  if (inGame && hasRolled) {
    disableRoll = true;
  }
  if (volcanoActive && (!isTurn || hasRolled)) {
    disableRoll = true;
  }
  if (volcanoActive && isTurn && turn && !turn.select) {
    disableRoll = false;
  }
  if (inGameOrder && hasGameOrderRolled) {
    disableRoll = true;
  }
  if (placement) {
    disableRoll = true;
  }

  const disableDone = volcanoActive || placeRoad || robberActions || !isTurn || !hasRolled;

  return (
    <Paper className="Actions">
      {edit === "" && <PlayerName name={name} setName={setName} />}
      <div className="Buttons">
        {name && alive === 1 && <Button onClick={resetGame}>Reset game</Button>}
        {name && inLobby && (
          <>
            <Button disabled={color && active >= 2 ? false : true} onClick={startClick}>
              Start game
            </Button>
            <Button disabled={color ? false : true} onClick={newTableClick}>
              New table
            </Button>
          </>
        )}
        {name && !color && (
          <Button disabled={color ? true : false} onClick={changeNameClick}>
            Change name
          </Button>
        )}
        {name && color && inLobby && (
          <Button disabled={color ? false : true} onClick={houseRulesClick}>
            House Rules
          </Button>
        )}
        {name && !inLobby && (
          <>
            <Button disabled={disableRoll} onClick={rollClick}>
              Roll Dice
            </Button>
            <Button
              disabled={volcanoActive || placeRoad || robberActions || !isTurn || !hasRolled || !haveResources}
              onClick={tradeClick}
            >
              Trade
            </Button>
            <Button
              disabled={volcanoActive || placeRoad || robberActions || !isTurn || !hasRolled || !haveResources}
              onClick={buildClicked}
            >
              Build
            </Button>
            <Button disabled={!(turn && turn.roll === 7 && priv && priv.mustDiscard > 0)} onClick={discardClick}>
              Discard
            </Button>
            {name && color && (
              <Button disabled={color ? false : true} onClick={houseRulesClick}>
                House Rules
              </Button>
            )}
            <Button disabled={disableDone} onClick={passClick}>
              Done
            </Button>
          </>
        )}
      </div>
    </Paper>
  );
};

export { Actions };
