/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/ban-ts-comment */
// @ts-nocheck
import React, { useEffect, useState, useContext, useRef, useMemo } from "react";
import equal from "fast-deep-equal";
import { assetsPath } from "./Common";
import "./Board.css";
import { GlobalContext } from "./GlobalContext";
import { Flock } from "./Bird";
import { Herd } from "./Sheep";

type BoardProps = {
  animations: boolean;
};

type CornerData = {
  index: number;
  x: number;
  y: number;
  // Add other properties as needed
};

type RoadData = {
  index: number;
  x: number;
  y: number;
  // Add other properties as needed
};

type PipData = {
  order: number;
  x: number;
  y: number;
  // Add other properties as needed
};

type TileData = {
  order: number;
  x: number;
  y: number;
  // Add other properties as needed
};

type TurnData = {
  // Define based on usage
};

type RulesData = {
  // Define based on usage
};

type PlacementData = Record<string, unknown>;

type CornerProps = {
  corner: CornerData;
};

type RoadProps = {
  road: RoadData;
};

type PipProps = {
  pip: PipData;
  className?: string;
};

type TileProps = {
  tile: TileData;
};

const rows = [3, 4, 5, 4, 3, 2]; /* The final row of 2 is to place roads and corners */

const hexRatio = 1.1547, // eslint-disable-line @typescript-eslint/no-loss-of-precision
  tileWidth = 67,
  tileHalfWidth = tileWidth * 0.5,
  tileHeight = tileWidth * hexRatio,
  tileHalfHeight = tileHeight * 0.5,
  radius = tileHeight * 2,
  borderOffsetX = 86 /* ~1/10th border image width... hand tuned */,
  borderOffsetY = 3;

/* Actual sizing */
const tileImageWidth = 90 /* Based on hand tuned and image width */,
  tileImageHeight = tileImageWidth / hexRatio,
  borderImageWidth = (2 + 2 / 3) * tileImageWidth /* 2.667 * .Tile.width */,
  borderImageHeight = borderImageWidth * 0.29; /* 0.29 * .Border.height */

const showTooltip = () => {
  const tooltip = document.querySelector(".Board .Tooltip") as HTMLElement;
  if (tooltip) tooltip.style.display = "flex";
};

const clearTooltip = () => {
  const tooltip = document.querySelector(".Board .Tooltip") as HTMLElement;
  if (tooltip) tooltip.style.display = "none";
};

const Board: React.FC<BoardProps> = ({ animations }) => {
  const { ws, sendJsonMessage } = useContext(GlobalContext);
  const board = useRef();
  const [transform, setTransform] = useState(1);
  const [pipElements, setPipElements] = useState<React.ReactElement[]>([]);
  const [borderElements, setBorderElements] = useState<React.ReactElement[]>([]);
  const [tileElements, setTileElements] = useState<React.ReactElement[]>([]);
  const [cornerElements, setCornerElements] = useState<React.ReactElement[]>([]);
  const [roadElements, setRoadElements] = useState<React.ReactElement[]>([]);
  const [signature, setSignature] = useState<string>("");
  const [generated, setGenerated] = useState<string>("");
  const [robber, setRobber] = useState<number>(-1);
  const [robberName, setRobberName] = useState<string[]>([]);
  const [pips, setPips] = useState<any>(undefined); // Keep as any for now, complex structure
  const [pipOrder, setPipOrder] = useState<any>(undefined);
  const [borders, setBorders] = useState<any>(undefined);
  const [borderOrder, setBorderOrder] = useState<any>(undefined);
  const [animationSeeds, setAnimationSeeds] = useState<any>(undefined);
  const [tiles, setTiles] = useState<any>(undefined);
  const [tileOrder, setTileOrder] = useState<number[]>([]);
  const [placements, setPlacements] = useState<PlacementData | undefined>(undefined);
  const [turn, setTurn] = useState<TurnData>({});
  const [state, setState] = useState<string>("");
  const [color, setColor] = useState<string>("");
  const [rules, setRules] = useState<RulesData>({});
  const [longestRoadLength, setLongestRoadLength] = useState<number>(0);
  const fields = useMemo(
    () => [
      "signature",
      "robber",
      "robberName",
      "pips",
      "pipOrder",
      "borders",
      "borderOrder",
      "tiles",
      "tileOrder",
      "placements",
      "turn",
      "state",
      "color",
      "longestRoadLength",
      "rules",
      "animationSeeds",
    ],
    []
  );

  const onWsMessage = (event) => {
    if (ws && ws !== event.target) {
      console.error(`Disconnect occur?`);
    }
    const data = JSON.parse(event.data);
    switch (data.type) {
      case "game-update":
        console.log(`board - game update`, data.update);
        if ("robber" in data.update && data.update.robber !== robber) {
          setRobber(data.update.robber);
        }

        if ("robberName" in data.update && data.update.robberName !== robberName) {
          setRobberName(data.update.robberName);
        }

        if ("state" in data.update && data.update.state !== state) {
          setState(data.update.state);
        }

        if ("rules" in data.update && !equal(data.update.rules, rules)) {
          setRules(data.update.rules);
        }

        if ("color" in data.update && data.update.color !== color) {
          setColor(data.update.color);
        }

        if ("longestRoadLength" in data.update && data.update.longestRoadLength !== longestRoadLength) {
          setLongestRoadLength(data.update.longestRoadLength);
        }

        if ("turn" in data.update) {
          if (!equal(data.update.turn, turn)) {
            console.log(`board - turn`, data.update.turn);
            setTurn(data.update.turn);
          }
        }

        if ("placements" in data.update && !equal(data.update.placements, placements)) {
          console.log(`board - placements`, data.update.placements);
          setPlacements(data.update.placements);
        }

        /* The following are only updated if there is a new game
         * signature */

        if ("pipOrder" in data.update && !equal(data.update.pipOrder, pipOrder)) {
          console.log(`board - setting new pipOrder`);
          setPipOrder(data.update.pipOrder);
        }

        if ("borderOrder" in data.update && !equal(data.update.borderOrder, borderOrder)) {
          console.log(`board - setting new borderOrder`);
          setBorderOrder(data.update.borderOrder);
        }

        if ("animationSeeds" in data.update && !equal(data.update.animationSeeds, animationSeeds)) {
          console.log(`board - setting new animationSeeds`);
          setAnimationSeeds(data.update.animationSeeds);
        }

        if ("tileOrder" in data.update && !equal(data.update.tileOrder, tileOrder)) {
          console.log(`board - setting new tileOrder`);
          setTileOrder(data.update.tileOrder);
        }

        if (data.update.signature !== signature) {
          console.log(`board - setting new signature`);
          setSignature(data.update.signature);
        }

        /* This is permanent static data from the server -- do not update
         * once set */
        if ("pips" in data.update && !pips) {
          console.log(`board - setting new static pips`);
          setPips(data.update.pips);
        }
        if ("tiles" in data.update && !tiles) {
          console.log(`board - setting new static tiles`);
          setTiles(data.update.tiles);
        }
        if ("borders" in data.update && !borders) {
          console.log(`board - setting new static borders`);
          setBorders(data.update.borders);
        }
        break;
      default:
        break;
    }
  };
  const refWsMessage = useRef(onWsMessage);
  useEffect(() => {
    refWsMessage.current = onWsMessage;
  });
  useEffect(() => {
    if (!ws) {
      return;
    }
    console.log("board - bind");
    const cbMessage = (e) => refWsMessage.current(e);
    ws.addEventListener("message", cbMessage);
    return () => {
      console.log("board - unbind");
      ws.removeEventListener("message", cbMessage);
    };
  }, [ws]);
  useEffect(() => {
    if (!sendJsonMessage) {
      return;
    }
    sendJsonMessage({
      type: "get",
      fields,
    });
  }, [sendJsonMessage, fields]);

  useEffect(() => {
    const boardBox = board.current.querySelector(".BoardBox");
    if (boardBox) {
      console.log(`board - setting transform scale to ${transform}`);
      boardBox.style.transform = `scale(${transform})`;
    }
  }, [transform]);

  const onResize = () => {
    if (!board.current) {
      return;
    }

    /* Adjust the 'transform: scale' for the BoardBox
     * so the board fills the Board
     *
     * The board is H tall, and H * hexRatio wide */
    const width = board.current.offsetWidth,
      height = board.current.offsetHeight;
    let _transform;
    if (height * hexRatio > width) {
      _transform = width / (450 * hexRatio); // eslint-disable-line @typescript-eslint/no-loss-of-precision
    } else {
      _transform = height / 450; // eslint-disable-line @typescript-eslint/no-loss-of-precision
    }

    if (transform !== _transform) {
      setTransform(_transform);
    }
  };

  const refOnResize = useRef(onResize);
  useEffect(() => {
    refOnResize.current = onResize;
  });
  useEffect(() => {
    const cbOnResize = (e) => refOnResize.current(e);
    window.addEventListener("resize", cbOnResize);
    return () => {
      window.removeEventListener("resize", cbOnResize);
    };
  }, [refOnResize]);

  onResize();

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

    console.log(`Generating static corner data... should only occur once per reload or socket reconnect.`);
    const onCornerClicked = (event, corner) => {
      let type;
      if (event.currentTarget.getAttribute("data-type") === "settlement") {
        type = "place-city";
      } else {
        type = "place-settlement";
      }
      ws.send(
        JSON.stringify({
          type,
          index: corner.index,
        })
      );
    };
    const Corner: React.FC<CornerProps> = ({ corner }) => {
      return (
        <div
          className="Corner"
          onMouseMove={(e) => {
            if (e.shiftPressed) {
              const tooltip = document.querySelector(".Board .Tooltip") as HTMLElement;
              tooltip.innerHTML = `<pre>${corner}</pre>`;
              showTooltip();
            }
          }}
          onClick={(event) => {
            onCornerClicked(event, corner);
          }}
          data-index={corner.index}
          style={{
            top: `${corner.top}px`,
            left: `${corner.left}px`,
          }}
        >
          <div className="Corner-Shape" />
        </div>
      );
    };

    const generateCorners = () => {
      let row = 0,
        rowCount = 0;
      let y = -8 + 0.5 * tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth,
        x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;
      let index = 0;
      const corners = [];
      let corner;

      for (let i = 0; i < 21; i++) {
        if (row > 2 && rowCount === 0) {
          corner = {
            index: index++,
            top: y - 0.5 * tileHalfHeight,
            left: x - tileHalfHeight,
          };
          corners.push(<Corner key={`corner-${index}}`} corner={corner} />);
        }

        corner = {
          index: index++,
          top: y,
          left: x,
        };
        corners.push(<Corner key={`corner-${index}}`} corner={corner} />);

        corner = {
          index: index++,
          top: y - 0.5 * tileHalfHeight,
          left: x + tileHalfHeight,
        };
        corners.push(<Corner key={`corner-${index}}`} corner={corner} />);

        if (++rowCount === rows[row]) {
          corner = {
            index: index++,
            top: y,
            left: x + 2 * tileHalfHeight,
          };
          corners.push(<Corner key={`corner-${index}}`} corner={corner} />);

          if (row > 2) {
            corner = {
              index: index++,
              top: y - 0.5 * tileHalfHeight,
              left: x + 3 * tileHalfHeight,
            };
            corners.push(<Corner key={`corner-${index}}`} corner={corner} />);
          }

          row++;
          rowCount = 0;
          y += tileHeight - 10.5;
          x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;
        } else {
          x += tileHeight;
        }
      }
      return corners;
    };

    setCornerElements(generateCorners());
  }, [ws, setCornerElements]);

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

    console.log(`Generating static road data... should only occur once per reload or socket reconnect.`);
    const Road: React.FC<RoadProps> = ({ road }) => {
      const onRoadClicked = (road) => {
        console.log(`Road clicked: ${road.index}`);
        if (!ws) {
          console.error(`board - onRoadClicked - ws is NULL`);
          return;
        }
        ws.send(
          JSON.stringify({
            type: "place-road",
            index: road.index,
          })
        );
      };

      return (
        <div
          className="Road"
          onClick={() => {
            onRoadClicked(road);
          }}
          data-index={road.index}
          style={{
            transform: `translate(-50%, -50%) rotate(${road.angle}deg)`,
            top: `${road.top}px`,
            left: `${road.left}px`,
          }}
        >
          <div className="Road-Shape" />
        </div>
      );
    };

    const generateRoads = () => {
      let row = 0,
        rowCount = 0;
      let y = -2.5 + tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth,
        x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;

      let index = 0;
      let road;

      const corners = [];

      for (let i = 0; i < 21; i++) {
        const lastRow = row === rows.length - 1;
        if (row > 2 && rowCount === 0) {
          road = {
            index: index++,
            angle: -60,
            top: y - 0.5 * tileHalfHeight,
            left: x - tileHalfHeight,
          };
          corners.push(<Road key={`road-${index}}`} road={road} />);
        }

        road = {
          index: index++,
          angle: 240,
          top: y,
          left: x,
        };
        corners.push(<Road key={`road-${index}}`} road={road} />);

        road = {
          index: index++,
          angle: -60,
          top: y - 0.5 * tileHalfHeight,
          left: x + tileHalfHeight,
        };
        corners.push(<Road key={`road-${index}}`} road={road} />);

        if (!lastRow) {
          road = {
            index: index++,
            angle: 0,
            top: y,
            left: x,
          };
          corners.push(<Road key={`road-${index}}`} road={road} />);
        }

        if (++rowCount === rows[row]) {
          if (!lastRow) {
            road = {
              index: index++,
              angle: 0,
              top: y,
              left: x + 2 * tileHalfHeight,
            };
            corners.push(<Road key={`road-${index}}`} road={road} />);
          }

          if (row > 2) {
            road = {
              index: index++,
              angle: 60,
              top: y - 0.5 * tileHalfHeight,
              left: x + 3 * tileHalfHeight,
            };
            corners.push(<Road key={`road-${index}}`} road={road} />);
          }

          row++;
          rowCount = 0;
          y += tileHeight - 10.5;
          x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;
        } else {
          x += tileHeight;
        }
      }
      return corners;
    };
    setRoadElements(generateRoads());
  }, [ws, setRoadElements]);

  /* Generate Pip, Tile, and Border elements */
  useEffect(() => {
    if (!ws) {
      return;
    }
    console.log(`board - Generate pip, border, and tile elements`);
    const Pip: React.FC<PipProps> = ({ pip, className }) => {
      const onPipClicked = (pip) => {
        if (!ws) {
          console.error(`board - sendPlacement - ws is NULL`);
          return;
        }
        ws.send(
          JSON.stringify({
            type: "place-robber",
            index: pip.index,
          })
        );
      };

      return (
        <div
          className={`Pip ${className}`}
          onClick={() => {
            onPipClicked(pip);
          }}
          data-roll={pip.roll}
          data-index={pip.index}
          style={{
            top: `${pip.top}px`,
            left: `${pip.left}px`,
            backgroundImage: `url(${assetsPath}/gfx/pip-numbers.png)`,
            backgroundPositionX: `${(100 * (pip.order % 6)) / 5}%`, // eslint-disable-line @typescript-eslint/no-loss-of-precision
            backgroundPositionY: `${(100 * Math.floor(pip.order / 6)) / 5}%`,
          }}
        >
          <div className="Pip-Shape" />
        </div>
      );
    };

    const generatePips = function (pipOrder) {
      let row = 0,
        rowCount = 0;
      let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth,
        x = -(rows[row] - 1) * 0.5 * tileHeight;
      let index = 0;
      let pip;
      return pipOrder.map((order) => {
        let volcano = false;
        pip = {
          roll: pips[order].roll,
          index: index++,
          top: y,
          left: x,
          order: order,
        };
        if ("volcano" in rules && rules[`volcano`].enabled && pip.roll === 7) {
          pip.order = pips.findIndex((pip) => pip.roll === rules[`volcano`].number);
          pip.roll = rules[`volcano`].number;
          volcano = true;
        }
        const div = <Pip className={volcano ? "Volcano" : ""} pip={pip} key={`pip-${order}`} />;

        if (++rowCount === rows[row]) {
          row++;
          rowCount = 0;
          y += tileWidth;
          x = -(rows[row] - 1) * 0.5 * tileHeight;
        } else {
          x += tileHeight;
        }

        return div;
      });
    };

    const Tile: React.FC<TileProps> = ({ tile }) => {
      const style: React.CSSProperties = {
        top: `${tile.top}px`,
        left: `${tile.left}px`,
        width: `${tileImageWidth}px`,
        height: `${tileImageHeight}px`,
        backgroundImage: `url(${assetsPath}/gfx/tiles-${tile.type}.png)`,
        backgroundPositionY: `-${tile.card * tileHeight}px`,
      };

      if (tile.type === "volcano") {
        style.transform = `rotate(-90deg)`;
        style.top = `${tile.top + 6}px`;
        style.transformOrigin = "0% 50%";
      }

      return (
        <div className="Tile" data-index={tile.index} style={{ ...style }}>
          <div className="Tile-Shape" />
        </div>
      );
    };

    const generateTiles = function (tileOrder, animationSeeds) {
      let row = 0,
        rowCount = 0;
      let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth,
        x = -(rows[row] - 1) * 0.5 * tileHeight;
      let index = 0;
      return tileOrder.map((order) => {
        const tile = Object.assign({}, tiles[order], { index: index++, left: x, top: y });
        const volcanoActive = "volcano" in rules && rules[`volcano`].enabled;

        if (
          "tiles-start-facing-down" in rules &&
          rules[`tiles-start-facing-down`].enabled &&
          state !== "normal" &&
          state !== "volcano" &&
          state !== "winner" &&
          (!volcanoActive || tile.type !== "desert")
        ) {
          tile.type = "jungle";
          tile.card = 0;
        }
        if (volcanoActive && tile.type === "desert") {
          tile.type = "volcano";
          tile.card = 0;
        }
        let div;

        if (tile.type === "wheat") {
          div = (
            <div key={`tile-${order}`}>
              {animations && (
                <Flock
                  count={Math.floor(1 + animationSeeds[index] * 2)}
                  style={{
                    top: `${tile.top - tileImageHeight * 0.5}px`,
                    left: `${tile.left - tileImageWidth * 0.5}px`,
                    width: `${tileImageWidth}px`,
                    height: `${tileImageHeight}px`,
                  }}
                />
              )}{" "}
              <Tile tile={tile} />
            </div>
          );
        } else if (tile.type === "sheep") {
          div = (
            <div key={`tile-${order}`}>
              {animations && (
                <Herd
                  count={Math.floor(1 + animationSeeds[index] * 4)}
                  style={{
                    top: `${tile.top - tileImageHeight * 0.5}px`,
                    left: `${tile.left - tileImageWidth * 0.5}px`,
                    width: `${tileImageWidth}px`,
                    height: `${tileImageHeight}px`,
                  }}
                />
              )}
              <Tile tile={tile} />
            </div>
          );
        } else {
          div = <Tile key={`tile-${order}`} tile={tile} />;
        }

        if (++rowCount === rows[row]) {
          row++;
          rowCount = 0;
          y += tileWidth;
          x = -(rows[row] - 1) * 0.5 * tileHeight;
        } else {
          x += tileHeight;
        }
        return div;
      });
    };

    const calculateBorderSlot = (side, e) => {
      const borderBox = document.querySelector(".Borders").getBoundingClientRect();
      let angle =
        ((360 + Math.floor(90 + (Math.atan2(e.pageY - borderBox.top, e.pageX - borderBox.left) * 180) / Math.PI)) %
          360) -
        side * 60;
      if (angle > 180) {
        angle = angle - 360;
      }
      let slot = 0;
      if (angle > -20 && angle < 5) {
        slot = 1;
      } else if (angle > 5) {
        slot = 2;
      }
      return slot;
    };

    const mouseEnter = (border, side, e) => {
      const slot = calculateBorderSlot(side, e);
      if (!border[slot]) {
        clearTooltip();
        return;
      }
      const tooltip = document.querySelector(".Board .Tooltip") as HTMLElement;
      tooltip.textContent =
        border[slot] === "bank" ? "3 of one kind for 1 resource" : `2 ${border[slot]} for 1 resource`;
      tooltip.style.top = `${e.pageY}px`;
      tooltip.style.left = `${e.pageX + 16}px`;
      showTooltip();
    };

    const mouseMove = (border, side, e) => {
      const slot = calculateBorderSlot(side, e);
      if (!border[slot]) {
        clearTooltip();
        return;
      }
      const tooltip = document.querySelector(".Board .Tooltip") as HTMLElement;
      tooltip.textContent =
        border[slot] === "bank" ? "3 of one kind for 1 resource" : `2 ${border[slot]} for 1 resource`;
      tooltip.style.top = `${e.pageY}px`;
      tooltip.style.left = `${e.pageX + 16}px`;
      showTooltip();
    };

    const mouseLeave = () => {
      clearTooltip();
    };

    const generateBorders = function (borderOrder) {
      const sides = 6;
      let side = -1;
      return borderOrder.map((order) => {
        const border = borders[order];
        side++;
        const x = +Math.sin(Math.PI - (side / sides) * 2 * Math.PI) * radius,
          y = Math.cos(Math.PI - (side / sides) * 2 * Math.PI) * radius;
        const prev = order === 0 ? 6 : order;
        const file = `borders-${order + 1}.${prev}.png`;
        const value = side;
        return (
          <div
            key={`border-${order}`}
            className="Border"
            border={border}
            onMouseEnter={(e) => {
              mouseEnter(border, value, e);
            }}
            onMouseMove={(e) => {
              mouseMove(border, value, e);
            }}
            onMouseLeave={mouseLeave}
            style={{
              width: `${borderImageWidth}px`,
              height: `${borderImageHeight}px`,
              top: `${y}px`,
              left: `${x}px`,
              transform: `rotate(${
                side * (360 / sides)
              }deg) translate(${borderOffsetX}px, ${borderOffsetY}px) scale(-1, -1)`,
              backgroundImage: `url(${assetsPath}/gfx/${file} )`,
            }}
          />
        );
      });
    };

    if (borders && borderOrder) {
      console.log(`board - Generate board - borders`);
      setBorderElements(generateBorders(borderOrder));
    }

    if (tiles && tileOrder && animationSeeds) {
      console.log(`board - Generate board - tiles`);
      setTileElements(generateTiles(tileOrder, animationSeeds));
    }

    /* Regenerate pips every time; it uses ws */
    if (pips && pipOrder) {
      console.log(`board - Generate board - pips`);
      setPipElements(generatePips(pipOrder));
    }

    if (signature && signature !== generated) {
      console.log(`board - Regnerating for ${signature}`);
      setGenerated(signature);
    }
  }, [
    signature,
    generated,
    pips,
    pipOrder,
    borders,
    borderOrder,
    tiles,
    tileOrder,
    animationSeeds,
    ws,
    state,
    rules,
    animations,
  ]);

  /* Re-render turn info after every render */
  useEffect(() => {
    if (!turn) {
      return;
    }
    let nodes = document.querySelectorAll(".Active");
    for (let i = 0; i < nodes.length; i++) {
      nodes[i].classList.remove("Active");
    }
    if (turn.roll) {
      nodes = document.querySelectorAll(`.Pip[data-roll="${turn.roll}"]`);
      for (let i = 0; i < nodes.length; i++) {
        const index = nodes[i].getAttribute("data-index");
        if (index !== null) {
          const tile = document.querySelector(`.Tile[data-index="${index}"]`);
          if (tile) {
            tile.classList.add("Active");
          }
        }
        nodes[i].classList.add("Active");
      }
    }
  });

  /* Re-render placements after every render */
  useEffect(() => {
    if (!placements) {
      return;
    }
    /* Set color and type based on placement data from the server */
    placements.corners.forEach((corner, index) => {
      const el = document.querySelector(`.Corner[data-index="${index}"]`);
      if (!el) {
        return;
      }
      if (turn.volcano === index) {
        el.classList.add("Lava");
      } else {
        el.classList.remove("Lava");
      }
      if (!corner.color) {
        el.removeAttribute("data-color");
        el.removeAttribute("data-type");
      } else {
        el.setAttribute("data-color", corner.color);
        el.setAttribute("data-type", corner.type);
      }
    });
    placements.roads.forEach((road, index) => {
      const el = document.querySelector(`.Road[data-index="${index}"]`);
      if (!el) {
        return;
      }
      if (!road.color) {
        el.removeAttribute("data-color");
      } else {
        if (road.longestRoad) {
          if (road.longestRoad === longestRoadLength) {
            el.classList.add("LongestRoad");
          } else {
            el.classList.remove("LongestRoad");
          }
          el.setAttribute("data-longest", road.longestRoad);
        } else {
          el.removeAttribute("data-longest");
        }
        el.setAttribute("data-color", road.color);
      }
    });

    /* Clear all 'Option' targets */
    let nodes = document.querySelectorAll(`.Option`);
    for (let i = 0; i < nodes.length; i++) {
      nodes[i].classList.remove("Option");
    }

    /* Add 'Option' based on turn.limits */
    if (turn && turn.limits) {
      if (turn.limits["roads"]) {
        turn.limits["roads"].forEach((index) => {
          const el = document.querySelector(`.Road[data-index="${index}"]`);
          if (!el) {
            return;
          }
          el.classList.add("Option");
          el.setAttribute("data-color", turn.color);
        });
      }
      if (turn.limits["corners"]) {
        turn.limits["corners"].forEach((index) => {
          const el = document.querySelector(`.Corner[data-index="${index}"]`);
          if (!el) {
            return;
          }
          el.classList.add("Option");
          el.setAttribute("data-color", turn.color);
        });
      }
      if (turn.limits["tiles"]) {
        turn.limits["tiles"].forEach((index) => {
          const el = document.querySelector(`.Tile[data-index="${index}"]`);
          if (!el) {
            return;
          }
          el.classList.add("Option");
        });
      }
      if (turn.limits["pips"]) {
        turn.limits["pips"].forEach((index) => {
          const el = document.querySelector(`.Pip[data-index="${index}"]`);
          if (!el) {
            return;
          }
          el.classList.add("Option");
        });
      }
    }

    /* Clear the robber */
    nodes = document.querySelectorAll(`.Pip.Robber`);
    for (let i = 0; i < nodes.length; i++) {
      nodes[i].classList.remove("Robber");
      ["Robert", "Roberta", "Velocirobber"].forEach((robberName) => nodes[i].classList.remove(robberName));
    }

    /* Place the robber */
    if (robber !== undefined) {
      const el = document.querySelector(`.Pip[data-index="${robber}"]`);
      if (el) {
        el.classList.add("Robber");
        el.classList.add(robberName);
      }
    }
  });

  const canAction = (action) => {
    return turn && Array.isArray(turn.actions) && turn.actions.indexOf(action) !== -1;
  };

  const canRoad =
    canAction("place-road") && turn.color === color && (state === "initial-placement" || state === "normal");

  const canCorner =
    (canAction("place-settlement") || canAction("place-city")) &&
    turn.color === color &&
    (state === "initial-placement" || state === "normal");

  const canPip =
    canAction("place-robber") && turn.color === color && (state === "initial-placement" || state === "normal");

  console.log(`board - tile elements`, tileElements);
  return (
    <div className="Board" ref={board}>
      <div className="Tooltip">tooltip</div>
      <div className="BoardBox">
        <div className="Borders" disabled>
          {borderElements}
        </div>
        <div className="Tiles" disabled>
          {tileElements}
        </div>
        <div className="Pips" disabled={!canPip}>
          {pipElements}
        </div>
        <div className="Corners" disabled={!canCorner}>
          {cornerElements}
        </div>
        <div className="Roads" disabled={!canRoad}>
          {roadElements}
        </div>
      </div>
    </div>
  );
};

export { Board };
