import * as React from 'react';
import { FunctionComponent, useState } from 'react';
import BoardView from './components/BoardView';
import { context } from './context'
import { Board, GameMove, Hole, Store } from './mancala';
import { Game } from './mancala';
import { decodeText, encodeText } from './rtmt/byte_util';
import { Bytes } from './rtmt/rtmt';
import { RTMTWS } from './rtmt/rtmt_websocket';
import { channel_game_move, channel_leave_game, channel_on_game_update, channel_on_game_user_leave } from './channel_names';
import Button from './components/Button';
import InfoPanel from './components/InfoPanel';

const testBoard = (): Board => {
  const board = new Board(
    [new Hole(0), new Hole(4), new Hole(4), new Hole(3), new Hole(2), new Hole(1)],
    [new Hole(4), new Hole(4), new Hole(4), new Hole(4), new Hole(4), new Hole(10)],
    new Store(0), new Store(0))
  return board
}

const testGame = new Game("0", "1", testBoard(), "player2", "playing")

type ConnectionState = "connecting" | "error" | "connected" | "reconnecting"

const Home: FunctionComponent<{ initial?: number }> = ({ initial = 0 }) => {
  const [userKey, setUserKey] = useState(undefined);

  const [connectionState, setConnetionState] = useState<ConnectionState>("connecting")

  const [game, setGame] = useState<Game>(undefined)

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

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

  const onConnectionDone = () => {
    setConnetionState("connected")
  }

  const onConnectionLost = () => {
    connectToServer("reconnecting")
  }

  const onConnectionError = (event: Event) => {
    setConnetionState("error")
  }

  const connectToServer = (connectionState: ConnectionState) => {
    setConnetionState(connectionState)
    context.userKeyStore.getUserKey((userKey: string) => {
      setUserKey(userKey)
      const rtmtws = context.rtmt as RTMTWS
      if (rtmtws) {
        rtmtws.initWebSocket(userKey, onConnectionDone, onConnectionLost, onConnectionError)
      } else {
        console.log("context.rtmt is not RTMTWS");
      }
    })
  }

  const listenMessages = () => {
    context.rtmt.listenMessage(channel_on_game_update, (message: Bytes) => {
      const newGame: Game = JSON.parse(decodeText(message))
      console.log("on game update");
      console.log(newGame);
      setGame(new Game(newGame.player1, newGame.player2, newGame.board, newGame.turn, newGame.state))
    })

    context.rtmt.listenMessage(channel_on_game_update, (message: Bytes) => {
      const newGame: Game = JSON.parse(decodeText(message))
      console.log("on game update");
      console.log(newGame);
      setGame(new Game(newGame.player1, newGame.player2, newGame.board, newGame.turn, newGame.state))
    })

    context.rtmt.listenMessage("on_game_start", (message) => {
      const newGame: Game = JSON.parse(decodeText(message))
      console.log("on_game_start");
      console.log(newGame);
      setGame(new Game(newGame.player1, newGame.player2, newGame.board, newGame.turn, newGame.state))
    })

    context.rtmt.listenMessage("on_game_crashed", (message) => {
      const newCrashMessage = decodeText(message)
      console.log("on_game_crash");
      console.log(newCrashMessage);
      setCrashMessage(newCrashMessage)
    })

    context.rtmt.listenMessage(channel_on_game_user_leave, (message) => {
      const userKeyWhoLeave = decodeText(message)
      console.log("on_game_user_leave");
      console.log(channel_on_game_user_leave);
      setUserKeyWhoLeave(userKeyWhoLeave)
    })
  }

  React.useEffect(() => {
    listenMessages()
    connectToServer("connecting")
  }, [])

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

  const newGameClick = () => {
    resetGameState()
    context.rtmt.sendMessage("new_game", new Uint8Array())
  }

  const leaveGame = () => {
    context.rtmt.sendMessage(channel_leave_game, new Uint8Array())
  }

  const onHoleSelect = (index: number, hole: Hole) => {
    const gameMove: GameMove = { index: index }
    context.rtmt.sendMessage(channel_game_move, encodeText(JSON.stringify(gameMove)))
  }

  const showConnectionState = connectionState != "connected"

  const connectionStateText = () => {
    let map: { [key: string]: string } = {
      "connecting": context.texts.Connecting,
      "connected": context.texts.Connected,
      "error": context.texts.CannotConnect,
      "reconnecting": context.texts.ConnectingAgain
    };

    return map[connectionState]
  }

  const renderNewGameButton = () => {
    const newGame = <Button text={context.texts.NewGame} color="white" onClick={newGameClick} />
    if (userKeyWhoLeave) {
      return newGame
    }
    if (crashMessage) {
      return newGame
    }
    if (!game) {
      return newGame
    } else if (game.state == "ended") {
      return newGame
    }
    return <></>
  }

  return <div style={{
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    background: "#EEEEEE",
    flex: "1",
  }}>
    {showConnectionState &&
      <div style={{
        position: "absolute",
        bottom: "0px",
        left: "0px",
        padding: "15px 15px 5px 5px",
        borderTopRightRadius: "1vw",
        minWidth: "10vw",
        minHeight: "1vw",
        background: "grey"
      }}>
        {connectionStateText()}
      </div>}
    <div style={{
      padding: "0px 50px",
      background: "rgb(228, 228, 228)",
      display: 'flex',
      flexDirection: "row",
      alignItems: "center",
      justifyContent: "space-between",
      alignSelf: "stretch"
    }}>
      <h1 style={{ margin: "10px 0px" }}>{context.texts.Mancala}</h1>
      <div>
        {renderNewGameButton()}
        {game && !userKeyWhoLeave && < Button color="white" text={context.texts.Leave} onClick={leaveGame} />}
      </div>

    </div>
    <InfoPanel game={game} crashMessage={crashMessage} userKey={userKey} userKeyWhoLeave={userKeyWhoLeave} />
    {game && <BoardView userKey={userKey} game={game} onHoleSelect={onHoleSelect} />}
  </div >
}

export default Home

function channel_game_user_leave(channel_game_user_leave: any, arg1: (message: Uint8Array) => void) {
  throw new Error('Function not implemented.');
}
