import { Component, createEffect, createSignal, Match, Show, Switch } from 'solid-js';
import createWebsocket from '@solid-primitives/websocket';
import { wsUrl } from './constants';
import Spinner from './components/Spinner';
import Welcome from './components/Welcome';
import { Board as BoardData, GameEvent, Move, ServerChessEvent, Side } from './events';
import Board from './components/Board';
import Popup from './components/Popup';

interface Props {
  gameId: string;
}

const App: Component<Props> = (props) => {
  const [board, setBoard] = createSignal<BoardData>(Array(64).fill(null));
  const [possibleMoves, setPossibleMoves] = createSignal<Move[]>([]);
  const [side, setSide] = createSignal<Side | null>(null);
  const [currentEvent, setCurrentEvent] = createSignal<GameEvent | null>(null);

  function handleEvent(e: MessageEvent<string>) {
    const data = JSON.parse(e.data);
    const event = ServerChessEvent.parse(data);
    if (event.event === 'BoardUpdate') {
      setBoard(event.data.board);
    } else if (event.event === 'PossibleMoves') {
      setPossibleMoves(event.data.moves);
    } else if (event.event === 'StartGame') {
      setSide(event.data.side);
    } else if (event.event === 'GameEvent') {
      setCurrentEvent(event.data);
    } else if (event.event === 'ClearGameEvent') {
      setCurrentEvent(null);
    }
  }

  const [connect, disconnect, send, state, socket] = createWebsocket(wsUrl(props.gameId), handleEvent, console.error);

  function joinGame() {
    connect();
    setSide(null);
    setBoard(Array(64).fill(null));
    setPossibleMoves([]);
    setCurrentEvent(null);
  }

  function makeMove(move: Move) {
    send(JSON.stringify({
      event: 'MakeMove',
      data: {
        move,
      },
    }));
  }

  return <Switch fallback={<Spinner />}>
    <Match when={state() === WebSocket.CLOSED}>
      <Welcome gameId={props.gameId} joinGame={() => joinGame()} />
    </Match>
    <Match when={state() === WebSocket.CONNECTING}>
      <Spinner />
    </Match>
    <Match when={state() === WebSocket.OPEN}>
      <Show when={side() !== null} fallback={<>
        <h1>Waiting for opponent...</h1>
        <Spinner />
      </>}>
        <Board board={board} moves={possibleMoves} makeMove={makeMove} side={side()!} />
      </Show>
      <Show when={currentEvent() !== null}>
        <Popup {...currentEvent()!} />
      </Show>
    </Match>
  </Switch>
};

export default App;
