import React, { useContext, useEffect } from 'react';
import { GamesStateContext, GamesGuideContext } from '../context/games';
import { Routes, Route, Link } from 'react-router-dom';

import NewGame from './games/NewGame';
import { GameProposalSelector, ActiveGameSelector, GameArchiveSelector } from './games/GameSelector';
import { Create, Accept, Reject, Cancel, DrawRequest, DrawAccept, DrawReject, Surrender, Backward, Forward } from './games/ActionPanel';
import GameBoard from './games/GameBoard';
import { nextStone } from '../components/Checkers';
import Message2Opponent from './games/Message2Opponent';
import Counter from '../components/Counter';

import './Games.css';

export default function Games({ games, players }) {
  const gamesState = games.state;
  const gamesDispatchGuide = games.dispatchGuide;

  useEffect(() => {
    gamesDispatchGuide({ type: 'sync', gamesState });
  }, [gamesState, gamesDispatchGuide]);

  return (
    <GamesStateContext.Provider value={gamesState} >
      <GamesGuideContext.Provider value={games.guide} >
        <div className='Games'>

          <div className='left-side'>
            <ViewSelector />
            <ViewProvider dispatchGuide={gamesDispatchGuide} players={players} />
          </div>

          <div className='right-side'>
            <ActionPanel gamesApi={games.api} />
            <GameBoardRoutes dispatchGuide={gamesDispatchGuide} gamesApi={games.api} username={players.user.name} />
            <Message2OpponentRoutes dispatchGuide={gamesDispatchGuide} />
          </div>

        </div >
      </GamesGuideContext.Provider>
    </GamesStateContext.Provider>
  )
};

function ViewSelector() {
  const guide = useContext(GamesGuideContext);

  return (
    <nav className='ViewSelector'>
      <div className='Container' >
        <Link to='new'>New</Link>
        <Link to='proposal'>Proposal<Counter number={guide.awaiting.proposal} /></Link>
        <Link to='active'  >Active<Counter number={guide.awaiting.active} /></Link>
        <Link to='archive' >Archive</Link>
      </div>
    </nav>
  )
}

function ViewProvider({ dispatchGuide, players }) {

  return (
    <div className='ViewProvider'>
      <Routes>

        <Route path='new' element={
          <NewGame
            players={players}
            setPlayers={(opponentName, myColor) => dispatchGuide({ type: 'nextNewGame', opponentName, myColor })}
          />
        } />

        <Route path='proposal' element={
          <GameProposalSelector onSelect={(uuid) => dispatchGuide({ type: 'selectedUUID', proposal: uuid })} />
        } />

        <Route path='active' element={
          <ActiveGameSelector onSelect={(uuid) => dispatchGuide({ type: 'selectedUUID', active: uuid })} />
        } />

        <Route path='archive' element={
          <GameArchiveSelector onSelect={(uuid) => dispatchGuide({ type: 'selectedUUID', archive: uuid })} />
        } />

      </Routes>
    </div>
  )
}

function ActionPanel({ gamesApi }) {
  const games = useContext(GamesStateContext);
  const guide = useContext(GamesGuideContext);

  const fromUUID = (uuid) => (!uuid) ? [{}, null] :
    [
      games.find((game) => game.uuid === uuid) || {}, // game
      guide.UUIDpushing[uuid]                         // pushing
    ];

  return (
    <div className='ActionPanel'>
      <Routes>

        <Route path='new' element={
          <Create
            getGame={() => [guide.newGame, guide.newGame.isPushing]}
            onClick={(req) => gamesApi.pushNewGame(req)}
          />
        } />

        <Route path='proposal' element={[
          <Accept key={1}
            getGame={() => fromUUID(guide.selectedUUID.proposal)}
            onClick={(req) => gamesApi.pushGameProposalAccept(req)}
          />,
          <Reject key={2}
            getGame={() => fromUUID(guide.selectedUUID.proposal)}
            onClick={(req) => gamesApi.pushGameProposalReject(req)}
          />,
          <Cancel key={3}
            getGame={() => fromUUID(guide.selectedUUID.proposal)}
            onClick={(req) => gamesApi.pushGameProposalCancel(req)}
          />
        ]} />

        <Route path='active' element={[
          <DrawRequest key={1}
            getGame={() => fromUUID(guide.selectedUUID.active)}
            onClick={(req) => gamesApi.pushGameDrawRequest(req)}
          />,
          <DrawAccept key={2}
            getGame={() => fromUUID(guide.selectedUUID.active)}
            onClick={(req) => gamesApi.pushGameDrawAccept(req)}
          />,
          <DrawReject key={3}
            getGame={() => fromUUID(guide.selectedUUID.active)}
            onClick={(req) => gamesApi.pushGameDrawReject(req)}
          />,
          <Surrender key={4}
            getGame={() => fromUUID(guide.selectedUUID.active)}
            onClick={(req) => gamesApi.pushGameSurrender(req)} />
        ]} />

        <Route path='archive' element={[
          <Backward key={1} />,
          <Forward key={2} />
        ]} />

      </Routes>
    </div>
  )
}

function GameBoardRoutes({ dispatchGuide, gamesApi, username }) {
  const games = useContext(GamesStateContext);
  const guide = useContext(GamesGuideContext);

  const fromUUID = (uuid) => (!uuid) ? [{}, null, null] :
    [
      games.find((game) => game.uuid === uuid) || {}, // game
      guide.UUIDpushing[uuid],                        // pushing
      guide.UUIDerror[uuid]                           // error (aka bad move)
    ];

  const onStoneClick = (uuid, cellId) => {
    let board = { ...guide.newGame.board };
    board[cellId] = nextStone(board[cellId]);
    dispatchGuide({ type: 'nextNewGame', board });
  }

  return (
    <Routes>

      <Route path='new' element={
        <GameBoard
          username={username}
          getGame={() => [guide.newGame, null]}
          onStoneClick={onStoneClick}
        />
      } />

      <Route path='proposal' element={
        <GameBoard
          username={username}
          getGame={() => fromUUID(guide.selectedUUID.proposal)}
        />
      } />

      <Route path='active' element={
        <GameBoard
          username={username}
          getGame={() => fromUUID(guide.selectedUUID.active)}
          onStoneMove={(uuid, move) => gamesApi.pushGameMove({ uuid, move, message: guide.UUIDmessage[uuid] })}
          dispatchGuide={dispatchGuide}
        />
      } />

      <Route path='archive' element={
        <GameBoard
          username={username}
          getGame={() => fromUUID(guide.selectedUUID.archive)}
        />
      } />

    </Routes>
  )
}

function Message2OpponentRoutes({ dispatchGuide }) {
  const guide = useContext(GamesGuideContext);

  const getMessage = (uuid) => !uuid ? undefined : // <<-- appears as inactive message field
    guide.UUIDmessage[uuid] || '';

  return (
    <Routes>

      <Route path='new' element={
        <Message2Opponent
          getMessage={() => guide.newGame.message}
          setMessage={(message) => dispatchGuide({ type: 'nextNewGame', message })} />
      } />

      <Route path='active' element={
        <Message2Opponent
          getMessage={() => getMessage(guide.selectedUUID.active)}
          setMessage={(message) => dispatchGuide({ type: 'UUIDmessage', message, uuid: guide.selectedUUID.active })} />
      } />

    </Routes>
  )
}