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 Switch from "@mui/material/Switch";
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableRow from "@mui/material/TableRow";

// import "./HouseRules.css";

import boardImg from "./assets/category-board.png";
import expansionImg from "./assets/category-expansion.png";
import rollingImg from "./assets/category-rolling.png";
import rulesImg from "./assets/category-rules.png";
import volcanoTile from "./assets/single-volcano.png";

import { GlobalContext } from "./GlobalContext";
import { Placard } from "./Placard";
import Box from "@mui/material/Box/Box";
import { Typography } from "@mui/material";

const categoryImages: { [key: string]: string } = {
  board: boardImg,
  expansion: expansionImg,
  rolling: rollingImg,
  rules: rulesImg,
};

/* eslint-disable @typescript-eslint/no-explicit-any */

interface VolcanoProps {
  sendJsonMessage: (message: any) => void;
  rules: any;
  field: string;
  disabled: boolean;
}

/* Volcano based on https://www.ultraboardgames.com/catan/the-volcano.php */
const Volcano: React.FC<VolcanoProps> = ({ sendJsonMessage, rules, field, disabled }) => {
  const init =
    Math.random() > 0.5
      ? Math.floor(8 + Math.random() * 5) /* Do not include 7 */
      : Math.floor(2 + Math.random() * 5); /* Do not include 7 */
  const [number, setNumber] = useState<number>(
    field in rules && "number" in rules[field] ? rules[field].number : init
  );
  const [gold, setGold] = useState<boolean>(
    field in rules && "gold" in rules[field] ? rules[field].gold : false
  );

  console.log(`house-rules - ${field} - `, rules[field]);

  useEffect(() => {
    if (field in rules) {
      setGold("gold" in rules[field] ? rules[field].gold : true);
      setNumber("number" in rules[field] ? rules[field].number : init);
      let update = false;
      if (!("gold" in rules[field])) {
        rules[field].gold = true;
        update = true;
      }
      if (!("number" in rules[field])) {
        rules[field].number = init;
        update = true;
      }

      if (update && sendJsonMessage) {
        sendJsonMessage({
          type: "rules",
          rules: rules,
        });
      }
    }
  }, [rules, field, init, sendJsonMessage]);

  const toggleGold = () => {
    if (!sendJsonMessage) return;
    rules[field].gold = !gold;
    rules[field].number = number;
    setGold(rules[field].gold);

    sendJsonMessage({
      type: "rules",
      rules: rules,
    });
  };

  const update = (delta: number) => {
    if (!sendJsonMessage) return;
    let value = number + delta;
    if (value < 2 || value > 12) {
      return;
    }
    /* Number to trigger Volcano cannot be 7 */
    if (value === 7) {
      value = delta > 0 ? 8 : 6;
    }
    setNumber(value);
    rules[field].gold = gold;
    rules[field].number = value;
    sendJsonMessage({
      type: "rules",
      rules: rules,
    });
  };

  return (
    <Box
      className="Volcano"
      sx={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        gap: 2,
        marginTop: 2,
      }}
    >
      <Box
        sx={{
          display: "flex",
          flexDirection: "row",
          alignItems: "center",
          gap: 2,
        }}
      >
        <img
          src={volcanoTile}
          alt={"Volcano"}
          style={{ width: "100px", height: "100px" }}
        />
        <div>
          The Volcano replaces the Desert. When the Volcano erupts, roll a die
          to determine the direction the lava will flow. One of the six
          intersections on the Volcano tile will be affected. If there is a
          settlement on the selected intersection, it is destroyed!
        </div>
      </Box>
      <div>
        Remove it from the board (its owner may rebuild it later). If a city is
        located there, it is reduced to a settlement! Replace the city with a
        settlement of its owner&apos;s color. If he has no settlements
        remaining, the city is destroyed instead.
      </div>
      <div>
        The presence of the Robber on the Volcano does not prevent the Volcano
        from erupting.
      </div>
      <div>
        Roll <b>{number}</b> and the Volcano erupts!
        <Button onClick={() => update(+1)}>up</Button>&nbsp;/&nbsp;
        <Button onClick={() => update(-1)}> down</Button>
      </div>
      <Paper sx={{ flexGrow: 1, width: "100%" }}>
        <Table>
          <TableRow>
            <TableCell>
              <b>Volcanoes have gold!</b>
              <br />
              Volcano can produce resources when its number is rolled.
            </TableCell>
            <TableCell>
              <Switch
                size={"small"}
                className="RuleSwitch"
                checked={gold}
                onChange={() => toggleGold()}
                {...{ disabled }}
              />
            </TableCell>
          </TableRow>
          {gold && (
            <TableRow>
              <TableCell colSpan={3}>
                <Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
                  <div>
                    Volcanoes tend to be rich in valuable minerals such as gold
                    or gems. Each settlement that is adjacent to the Volcano
                    when it erupts may produce any one of the five resources
                    it&apos;s owner desires.
                  </div>
                  <div>
                    Each city adjacent to the Volcano may produce any two
                    resources. This resource production is taken before the
                    results of the volcano eruption are resolved. Note that
                    while the Robber can not prevent the Volcano from erupting,
                    he does prevent any player from producing resources from the
                    Volcano hex if he has been placed there.
                  </div>
                </Box>
              </TableCell>
            </TableRow>
          )}
        </Table>
      </Paper>
    </Box>
  );
};

interface VictoryPointsProps {
  sendJsonMessage: (message: any) => void;
  rules: any;
  field: string;
}

const VictoryPoints: React.FC<VictoryPointsProps> = ({ sendJsonMessage, rules, field }) => {
  const minVP = 10;
  const [points, setPoints] = useState<number>(rules[field].points || minVP);
  console.log(`house-rules - ${field} - `, rules[field]);

  if (!(field in rules)) {
    rules[field] = {
      points: minVP,
    };
  }

  if (rules[field].points && rules[field].points !== points) {
    setPoints(rules[field].points);
  }

  const update = (value: number) => {
    if (!sendJsonMessage) return;
    const points = (rules[field].points || minVP) + value;
    if (points < minVP) {
      return;
    }
    if (points !== rules[field].points) {
      setPoints(points);
      rules[field].points = points;
      sendJsonMessage({
        type: "rules",
        rules: rules,
      });
    }
  };

  return (
    <Box className="VictoryPoints" sx={{display: 'flex', flexDirection: 'column', gap: 2, marginTop: 2}}>
      <Box>
      The first to reach <b>{points}</b> points wins!
      <Button onClick={() => update(+1)}>up</Button>&nbsp;/&nbsp;
      <Button onClick={() => update(-1)}> down</Button>
      </Box>
      <Box>
        This flexible twist of a rule lets you customize the number of Victory Points needed to claim victory, whether youre aiming for a quick 7-point skirmish or a marathon 12-point conquest. Adjust the goal to match your mood—keep it low for a fast-paced showdown or crank it up for an epic battle of strategy and luck, ensuring every game feels fresh and perfectly suited to your crew’s competitive spirit!
        </Box>
    </Box>
  );
};

interface HouseRulesProps {
  houseRulesActive: boolean;
  setHouseRulesActive: React.Dispatch<React.SetStateAction<boolean>>;
}

const HouseRules: React.FC<HouseRulesProps> = ({
  houseRulesActive,
  setHouseRulesActive,
}) => {
  const { ws, name, sendJsonMessage } = useContext(GlobalContext);
  const [rules, setRules] = useState<any>({});
  const [state, setState] = useState<any>({});
  const [gameState, setGameState] = useState<string>("");

  const fields = useMemo(() => ["state", "rules"], []);
  const onWsMessage = (event: MessageEvent) => {
    const data = JSON.parse(event.data);
    switch (data.type) {
      case "game-update":
        console.log(`house-rules - game-update: `, data.update);
        if ("state" in data.update && data.update.state !== gameState) {
          setGameState(data.update.state);
        }
        if ("rules" in data.update && !equal(rules, data.update.rules)) {
          setRules(data.update.rules);
        }
        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 dismissClicked = useCallback(() => {
    setHouseRulesActive(false);
  }, [setHouseRulesActive]);

  const setRule = useCallback(
    (event: React.ChangeEvent<HTMLInputElement>, key: string) => {
      if (!sendJsonMessage) return;
      const checked = event.target.checked;
      console.log(`house-rules - set rule ${key} to ${checked}`);
      rules[key].enabled = checked;
      setRules({ ...rules });
      sendJsonMessage({
        type: "rules",
        rules: rules,
      });
    },
    [rules, sendJsonMessage]
  );

  const ruleList = useMemo(
    () =>
      [
        {
          key: "volcano",
          label: "Volcanoes are a lava fun!",
          description: "A volcano is on the island! Let the lava flow!",
          category: "board",
          defaultChecked: false,
          element: (
            <Volcano
              sendJsonMessage={sendJsonMessage}
              rules={rules}
              field={"volcano"}
              disabled={gameState !== "lobby"}
            />
          ),
        },
        {
          key: "victory-points",
          label: "More victory points",
          description: "Customize how many Victory Points are required to win.",
          category: "rules",
          defaultChecked: false,
          element: (
            <VictoryPoints sendJsonMessage={sendJsonMessage} rules={rules} field={"victory-points"} />
          ),
        },
        {
          key: "tiles-start-facing-down",
          label: "Tiles start facing down",
          description:
            "Resource tiles start upside-down while placing starting settlements.",
          category: "board",
          defaultChecked: false,
          element: (
            <div>
              Once all players have placed their initial settlements and roads,
              the tiles are flipped and you discover what the resources are.
            </div>
          ),
        },
        {
          key: "most-developed",
          label: "You are so developed!",
          description:
            "The player with the most development cards (more than 4) receives 2VP.",
          category: "expansion",
          defaultChecked: false,
          element: (
            <Box sx={{ display: "block", flexDirection: "column" }}>
              <Placard
                sx={{
                  float: "left",
                  shapeOutside: "inset(0)" /* Text wraps the full rectangle */,
                  clipPath: "inset(0)" /* Ensures proper wrapping area */,
                  marginRight: "1rem",
                  marginBottom: "1rem",
                }}
                type="most-developed"
              />
              <Typography variant="body2">
                This card rewards the player who amasses more than 4 development
                cards with a glorious 2 Victory Points, turning your strategic
                savvy into a medieval masterpiece complete with towering cities
                and bustling fields. Picture yourself snagging this beautifully
                illustrated card—featuring hardworking villagers and a majestic
                castle!
              </Typography>
            </Box>
          ),
        },
        {
          key: "port-of-call",
          label: "Another round of port?",
          description:
            "The player with the most harbor ports (more than 2) receives 2VP.",
          category: "expansion",
          defaultChecked: false,
          element: (
            <Box sx={{ display: "block", flexDirection: "column" }}>
              <Placard
                sx={{
                  float: "left",
                  shapeOutside: "inset(0)" /* Text wraps the full rectangle */,
                  clipPath: "inset(0)" /* Ensures proper wrapping area */,
                  marginRight: "1rem",
                  marginBottom: "1rem",
                }}
                type="port-of-call"
              />
              <Typography variant="body2">
                Raise your mugs and hoist the sails! This lively card rewards
                the most seasoned seafarer among the settlers. When you control
                more than two harbor ports, you claim this card and earn 2
                Victory Points as a tribute to your mastery of the seas. But
                beware — other ambitious captains are watching closely! The
                moment someone else builds a larger network of harbors, they’ll
                steal both the card and the glory right from under your nose.
                Keep those ships moving and never let your rivals toast to your
                downfall!
              </Typography>
            </Box>
          ),
        },
        {
          key: "slowest-turn",
          label: "Why you play so slow?",
          description:
            "The player with the longest turn idle time (longer than 2 minutes) so far loses 2VP.",
          category: "expansion",
          defaultChecked: false,
          element: (
            <Box sx={{ display: "block", flexDirection: "column" }}>
              <Placard
                sx={{
                  float: "left",
                  shapeOutside: "inset(0)" /* Text wraps the full rectangle */,
                  clipPath: "inset(0)" /* Ensures proper wrapping area */,
                  marginRight: "1rem",
                  marginBottom: "1rem",
                }}
                type="longest-turn"
              />
              <Typography variant="body2" sx={{ marginTop: "1rem" }}>
                If your turn idle time drags on past 2 minutes, you’re slapped
                with a -2 Victory Points penalty and handed this charming
                card—featuring industrious villagers raking hay with a castle
                looming in the background—until someone even slower takes it
                from you with a sheepish grin!
              </Typography>
            </Box>
          ),
        },
        {
          key: "roll-double-roll-again",
          label: "Roll double, roll again",
          description: "Roll again if you roll two of the same number.",
          category: "rolling",
          defaultChecked: false,
          element: (
            <div>
              If you roll doubles, players get those resources and then you must
              roll again.
              <Box sx={{ display: "block", fontWeight: "bold", pt: 1, pb: 1 }}>
                Note:
              </Box>
              This stacks with Two and Twelve are Synonyms. So if you roll
              double ones (2), you get resources for 2 and 12, then roll again!
            </div>
          ),
        },
        {
          key: "twelve-and-two-are-synonyms",
          label: "Twelve and Two are synonyms",
          description:
            "If twelve is rolled, two scores as well. And vice-versa.",
          category: "rolling",
          defaultChecked: false,
          element: (
            <div>
              If you roll a twelve or two, resources are triggered for both.
              <Box sx={{ display: "block", fontWeight: "bold", pt: 1, pb: 1 }}>
                Note:
              </Box>{" "}
              This stacks with Roll Double, Roll Again. So if you roll double
              sixes (12), you get resources for 2 and 12, then roll again!
            </div>
          ),
        },
        {
          key: "robin-hood-robber",
          label: "Robin Hood robber",
          description:
            "Robbers can't steal from players with two or less victory points.",
          category: "rules",
          defaultChecked: false,
          element: (
            <Typography variant="body2">
              This rule turns the robber into a noble thief, forbidding him from
              pilfering resources from players with two or fewer Victory
              Points—leaving the underdogs safe while the wealthier lords
              tremble. Watch as the tables turn with a wink and a grin, adding a
              layer of strategy where protecting the little guy might just be
              the key to your own rise to power!
            </Typography>
          ),
        },
      ].sort((a, b) => a.category.localeCompare(b.category)),
    [rules, setRules, state, ws, setRule, name, gameState]
  );

  if (!houseRulesActive) {
    return <></>;
  }

  return (
    <Paper
      sx={{
        p: 1,
        maxWidth: 600,
        margin: "1rem auto",
        flexDirection: "column",
        display: "flex",
      }}
      className="HouseRules"
      elevation={3}
    >
      <DialogTitle>House Rules</DialogTitle>
      <DialogContent>
        <TableContainer>
          <Table sx={{ tableLayout: "fixed" }}>
            <TableBody>
              {ruleList.map((item) => {
                const defaultChecked = item.defaultChecked;
                if (!(item.key in rules)) {
                  rules[item.key] = {
                    enabled: defaultChecked,
                  };
                }
                const checked = rules[item.key].enabled;
                if (checked !== state[item.key]) {
                  setState({ ...state, [item.key]: checked });
                }

                return (
                  <React.Fragment key={item.key}>
                    <TableRow>
                      <TableCell sx={{ width: "50px" }}>
                        {/* Fixed width for image */}
                        <img
                          src={categoryImages[item.category]}
                          alt={item.category}
                          style={{ width: "50px", height: "68px" }}
                        />
                      </TableCell>
                      <TableCell sx={{ width: "auto" }}>
                        <b>{item.label}</b>
                        <br />
                        {item.description}
                      </TableCell>
                      <TableCell sx={{ width: "32px" }}>
                        <Switch
                          size={"small"}
                          className="RuleSwitch"
                          checked={checked}
                          id={item.key}
                          onChange={(e) => setRule(e, item.key)}
                          disabled={gameState !== "lobby"}
                        />
                      </TableCell>
                    </TableRow>
                    {checked && (
                      <TableRow>
                        <TableCell colSpan={3}>{item.element}</TableCell>
                      </TableRow>
                    )}
                  </React.Fragment>
                );
              })}
            </TableBody>
          </Table>
        </TableContainer>
      </DialogContent>
      <DialogActions>
        <Button onClick={dismissClicked}>Close</Button>
      </DialogActions>
    </Paper>
  );
};

export { HouseRules };
