import React, {useState, useRef, useEffect} from 'react';
import io from 'socket.io-client';
import './App.css';
import Game from './Game';

interface GameState {
  bases: (string | null)[];
  outs: number;
  display_top_of_inning: boolean
  display_inning: number
  max_innings: number
  title: string
  weather_emoji: string
  weather_text: string
  away_name: string
  away_score: number
  home_name: string
  home_score: number
  pitcher: string
  batter: string
  update_emoji: string
  update_text: string
  is_league: boolean
  leagueoruser: string
}

type GameList = ([id: string, game: GameState] | null)[];

function App(props: {filter: string | null, gameId: string | null}) {

  let [games, setGames] = useState(new Array<[string, GameState]>());
  let [filter, setFilter] = useState("");
  useListener(setGames);

  let filters: string[] = [];
  games.forEach((game, id) => { if (game[1].is_league && !filters.includes(game[1].leagueoruser)) { filters.push(game[1].leagueoruser) }});

  let gameList = useRef(new Array<(string | null)>());
  let filterGames = games.filter((game, i) => filter === "" || game[1].leagueoruser === filter);
  updateList(gameList.current, filterGames);

  return (
    <div className="App">
      <Filters filterList={filters} selectedFilter={filter} onSelectNewFilter={(filter: string) => {gameList.current = []; setFilter(filter)}}/>
      <Grid gameList={gameList.current.map((val) => val !== null ? filterGames.find((game) => game[0] === val) as [string, GameState] : null )}/>
      <Footer has_games={filterGames.length > 0}/>
    </div>
  );
}

// App Utils

// connects to the given url (or host if none) and waits for state updates
const useListener = (onUpdate: (update: [string, GameState][]) => void, url: string | null = null) => {
  useEffect(() => {
    let socket = url ? io(url) : io();
    socket.on('connect', () => socket.emit('recieved', {}));
    socket.on('states_update', onUpdate);
    return () => {socket.disconnect()}
  }, [url])
}

// adds and removes games from list to keep it up to date, without relocating games already in place
function updateList(gameList: (string | null)[], games: [string, GameState][]) {

  //remove games no longer present
  for (let i = 0; i < gameList.length; i ++) {
    if (gameList[i] !== null && games.findIndex((val) => val[0] === gameList[i]) < 0) {
        gameList[i] = null;
    }
  }

  // add games not present
  for (let game of games) {
    if (!gameList.find((val) => val !== null && val === game[0])) {
      let firstEmpty = gameList.indexOf(null);
      if (firstEmpty < 0) {
        gameList.push(game[0])
      } else {
        gameList[firstEmpty] = game[0];
      }
    }
  }

  //remove trailing empty cells
  while (gameList[gameList.length-1] === null) {
    gameList.pop();
  }
}

function Filters (props: {filterList: string[], selectedFilter: string, onSelectNewFilter: (newFilter: string) => void}) {
  function Filter(innerprops: {title: string, filter:string} ) {
    return (
      <button className="filter"
              id={innerprops.filter === props.selectedFilter ? "selected_filter" : ""}
              onClick={() => props.onSelectNewFilter(innerprops.filter)}>
        {innerprops.title}
      </button>
    );
  }

  return (
    <div id="filters">
      <div>Filter:</div>
      <Filter title="All" filter="" key="" />
      {props.filterList.map((filter: string) => 
        <Filter title={filter} filter={filter} key={filter} />
      )}
    </div>
  );
}

function Grid(props: { gameList: GameList }) {
   return (
    <section className="container" id="container">
      {props.gameList.map((game) => {if (game) {
        return <Game gameId={game[0]} state={game[1]} key={game[0]}/>
      } else {
        return <div className="emptyslot"/>
      }})}
    </section>
  );
}

function Footer(props: { has_games: boolean }) {
  let text = props.has_games ? "" : "No games right now. Why not head over to Discord and start one?";
  return (
    <div id="footer">
      <div>{text}</div>
    </div>
  );
}

export default App;
export type { GameState };