import * as React from "react";
import { FunctionComponent, useEffect, useState } from "react";
import BoardView from "../components/board/BoardView";
import { RTMTWS } from "../rtmt/rtmt_websocket";
import {
  channel_game_move,
  channel_leave_game,
  channel_on_game_crashed,
  channel_on_game_start,
  channel_on_game_update,
  channel_on_game_user_leave,
  channel_on_user_connection_change,
} from "../const/channel_names";
import InfoPanel from "../components/InfoPanel";
import { CommonMancalaGame, MancalaGame, Pit } from "mancala.js";
import { GameMove } from "../models/GameMove";
import PitAnimator from "../animation/PitAnimator";
import BoardViewModel from "../viewmodel/BoardViewModel";
import { v4 } from "uuid";
import { getColorByBrightness } from "../util/ColorUtil";
import { Theme } from "../theme/Theme";
import HeaderBar from "../components/headerbar/HeaderBar";
import PageContainer from "../components/PageContainer";
import Row from "../components/Row";
import HeaderbarIcon from "../components/headerbar/HeaderbarIcon";
import HeaderbarTitle from "../components/headerbar/HeaderbarTitle";
import ThemeSwitchMenu from "../components/headerbar/ThemeSwitchMenu";
import Button from "../components/Button";
import BoardToolbar from "../components/board/BoardToolbar";
import UserStatus from "../components/UserStatus";
import Center from "../components/Center";
import CircularPanel from "../components/CircularPanel";
import useWindowDimensions from "../hooks/useWindowDimensions";
import { UserConnectionInfo } from "../models/UserConnectionInfo";
import { Context } from "../context/context";
import { ConnectionState } from "../models/ConnectionState";

const Home: FunctionComponent<{
  context: Context,
  userKey?: string,
  connectionState: ConnectionState
}> = ({ context, userKey, connectionState }) => {

  const [searchingOpponent, setSearchingOpponent] = useState<boolean>(false);

  const [game, setGame] = useState<CommonMancalaGame | undefined>(undefined);

  const [crashMessage, setCrashMessage] = useState<string | undefined>(undefined);

  const [userKeyWhoLeave, setUserKeyWhoLeave] = useState<string | undefined>(undefined);

  const [boardViewModel, setBoardViewModel] = useState<BoardViewModel | undefined>(undefined);

  const [boardId, setBoardId] = useState<string>("-1");

  const [pitAnimator, setPitAnimator] = useState<PitAnimator | undefined>(undefined);

  const [theme, setTheme] = useState<Theme | undefined>(undefined);

  // It is a flag for ongoing action such as send game move.
  // We have to block future actions if there is an ongoing action.
  const [hasOngoingAction, setHasOngoingAction] = useState<boolean>(false);

  const { height, width } = useWindowDimensions();

  const [isOpponentOnline, setIsOpponentOnline] = useState<boolean>(false);

  const listenMessages = (pitAnimator: PitAnimator) => {
    context.rtmt.listenMessage(channel_on_game_start, (message: Object) => {
      const newGame: CommonMancalaGame = message as CommonMancalaGame;
      const mancalaGame = MancalaGame.createFromMancalaGame(newGame);
      setSearchingOpponent(false);
      setGame(mancalaGame);
      pitAnimator.setNewGame(mancalaGame);
      setHasOngoingAction(false);
    });

    context.rtmt.listenMessage(channel_on_game_update, (message: Object) => {
      const newGame: CommonMancalaGame = message as CommonMancalaGame;
      const mancalaGame = MancalaGame.createFromMancalaGame(newGame);
      setGame(mancalaGame);
      pitAnimator.setUpdatedGame(mancalaGame);
      setHasOngoingAction(false);
    });

    context.rtmt.listenMessage(channel_on_game_crashed, (message: any) => {
      const newCrashMessage = message as string;
      console.error("on_game_crash");
      console.error(newCrashMessage);
      setCrashMessage(newCrashMessage);
    });

    context.rtmt.listenMessage(channel_on_game_user_leave, (message: any) => {
      const userKeyWhoLeave = message;
      setUserKeyWhoLeave(userKeyWhoLeave);
      setHasOngoingAction(false);
    });

    context.rtmt.listenMessage(channel_on_user_connection_change, (message: any) => {
      const userConnectionInfo = message as UserConnectionInfo;
      //todo: change this when implementing watch the game feature
      setIsOpponentOnline(userConnectionInfo.isOnline);
    })
  };

  const updateBoardViewModel = (boardViewModel: BoardViewModel) => {
    boardViewModel.id = v4();
    setBoardId(boardViewModel.id);
    setBoardViewModel(boardViewModel);
  };

  const resetGameState = () => {
    setGame(undefined);
    setCrashMessage(undefined);
    setUserKeyWhoLeave(undefined);
    setHasOngoingAction(false);
  };

  const getBoardIndex = (index: number) => {
    if (!game) return -1;
    if (userKey === game.player2Id) return index + game.board.pits.length / 2;
    return index;
  };

  const getOpponentId = () => game?.player1Id === userKey ? game?.player2Id : game?.player1Id;

  const checkHasAnOngoingAction = () => hasOngoingAction;

  React.useEffect(() => {
    setTheme(context.themeManager.theme);
    const pitAnimator = new PitAnimator(context, updateBoardViewModel);
    setPitAnimator(pitAnimator);
    listenMessages(pitAnimator);
    return () => {
      pitAnimator.dispose();
    };
  }, []);

  React.useEffect(() => {
    context.themeManager.onThemeChange = (theme) => {
      setTheme(theme);
      pitAnimator && game && updateBoardViewModel(pitAnimator.getBoardViewModelFromGame(game));
    };
  }, [boardViewModel]);

  const onNewGameClick = () => {
    resetGameState();
    setSearchingOpponent(true);
    context.rtmt.sendMessage("new_game", {});
  };

  const onLeaveGameClick = () => {
    context.rtmt.sendMessage(channel_leave_game, {});
  };

  const onPitSelect = (index: number, pit: Pit) => {
    if (checkHasAnOngoingAction()) {
      return;
    }
    setHasOngoingAction(true);
    if (!boardViewModel) return;
    //TODO : stoneCount comes from view model!
    if (pit.stoneCount === 0) {
      //TODO : warn user
      return;
    }
    boardViewModel.pits[getBoardIndex(index)].pitColor =
      context.themeManager.theme.pitSelectedColor;
    updateBoardViewModel(boardViewModel);
    const gameMove: GameMove = { index: index };
    context.rtmt.sendMessage(channel_game_move, gameMove);
  };

  const textColorOnBoard = getColorByBrightness(
    context.themeManager.theme.boardColor,
    context.themeManager.theme.textColor,
    context.themeManager.theme.textLightColor
  );
  const textColorOnAppBar = getColorByBrightness(
    context.themeManager.theme.appBarBgColor,
    context.themeManager.theme.textColor,
    context.themeManager.theme.textLightColor
  );
  const renderNewGameBtn = userKeyWhoLeave || !game || (game && game.state == "ended");
  const showBoardView = game && boardViewModel && userKey && true;
  const opponentUser = { id: getOpponentId() || "0", name: "Anonymous", isOnline: isOpponentOnline, isAnonymous: true };
  const user = { id: userKey || "1", name: "Anonymous", isOnline: connectionState === "connected", isAnonymous: true };

  const isMobile = width < 600;

  return (
    <PageContainer theme={theme!}>
      <HeaderBar color={theme?.appBarBgColor}>
        <Row>
          <HeaderbarIcon />
          <HeaderbarTitle title={context.texts.Mancala} color={textColorOnAppBar} />
        </Row>
        <Row>
          <ThemeSwitchMenu context={context} textColor={textColorOnAppBar} />
          <Button
            context={context}
            color={context.themeManager.theme.pitColor}
            text={renderNewGameBtn ? context.texts.NewGame : context.texts.Leave}
            onClick={renderNewGameBtn ? onNewGameClick : onLeaveGameClick} />
        </Row>
      </HeaderBar>
      <BoardToolbar style={{ justifyContent: "center" }} visible={showBoardView && isMobile || false}>
        <InfoPanel
          style={{ marginTop: "0.5rem", marginBottom: "0.5rem" }}
          context={context}
          game={game}
          crashMessage={crashMessage}
          userKey={userKey}
          userKeyWhoLeave={userKeyWhoLeave} />
      </BoardToolbar>
      <BoardToolbar style={{ alignItems: "flex-end" }} visible={showBoardView || false}>
        <UserStatus style={{
          marginBottom: "0.5rem", marginLeft: "6%", maxWidth: isMobile ? "40vw" : "30vw",
          width: isMobile ? "40vw" : "30vw"
        }} context={context} layoutMode="left" user={opponentUser} visible={showBoardView || false} />
        <InfoPanel
          style={{
            marginTop: "0.5rem", marginBottom: "0.5rem",
          }}
          context={context}
          game={game}
          crashMessage={crashMessage}
          userKey={userKey}
          userKeyWhoLeave={userKeyWhoLeave}
          visible={!isMobile} />
        <UserStatus style={{
          marginBottom: "0.5rem", marginRight: "6%", maxWidth: isMobile ? "40vw" : "30vw",
          width: isMobile ? "40vw" : "30vw"
        }} context={context} layoutMode="right" user={user} visible={showBoardView || false} />
      </BoardToolbar>
      {showBoardView ? (
        <BoardView
          userKey={userKey}
          game={game}
          boardId={boardId}
          boardViewModel={boardViewModel}
          context={context}
          onPitSelect={onPitSelect} />
      ) : searchingOpponent && (
        <Center>
          <CircularPanel color={context.themeManager.theme.boardColor}>
            <h4 style={{ margin: "0", color: textColorOnBoard }}>{`${context.texts.SearchingOpponent} ${context.texts.PleaseWait}...`}</h4>
          </CircularPanel>
        </Center>
      )}
    </PageContainer>
  );
};

export default Home;
