from datetime import datetime

class GameBoard:
  def __init__(self, game_id:str, width:int, height:int, ruleset:dict, source:str, map:str, snake_class):
    self.id = game_id
    self.width = width
    self.height = height
    self.type = ruleset["name"]
    self.snake_class = snake_class

    # What will get Stored
    self.winner_snake_names = None
    self.now_date = datetime.now()
    self.turns = []
    self.is_ladder = True if source == "ladder" else False
    self.ruleset = ruleset
    self.map = map
    self.url = self._get_game_url(True if ruleset["version"] == "cli" else False)

  # Setter Functions
  def _set_snakes(self, snakes:list[dict]):
    self.other_snakes = [ x for x in snakes if x["id"] != self.my_snake["id"] ]

  def _set_my_snake(self, my_snake:str):
    self.my_snake = my_snake

  def _set_food(self, food:list[dict]):
    self.food = food

  def _set_hazards(self, hazards:list[dict]):
    self.hazards = hazards

  def _set_turn(self, turn:int):
    self.turn = turn

  # Getter Functions
  def get_other_snakes(self):
    return self.other_snakes

  def get_my_snake(self):
    return self.my_snake

  def get_food(self):
    return self.food

  def get_hazard(self):
    return self.hazards

  def get_turn(self):
    return self.turn

  def get_dimension(self):
    return {"width": self.width, "height": self.height}

  def get_width(self):
    return self.width

  def get_height(self):
    return self.height

  def get_type(self):
    return self.type

  def get_my_snake_head(self):
    return self.my_snake["head"]

  def get_my_snake_body(self):
    return self.my_snake["body"]

  def get_my_snake_tail(self):
    return self.my_snake["body"][-1]

  def get_game_board_as_dict(self):
    snakes = [self.my_snake]
    snakes.extend(self.other_snakes)

    return {
      "height": self.height,
      "width": self.width,
      "snakes": snakes,
      "food": self.food,
      "hazards": self.hazards
      }

  # Game Functions
  def read_game_data(self, game_data:dict):
    self._set_food(game_data['board']['food'])
    self._set_hazards(game_data['board']['hazards'])

    self._set_my_snake(game_data['you'])
    self._set_snakes(game_data['board']['snakes'])

    self._set_turn(game_data["turn"])

  async def start_game(self, game_data:dict):
    self.init_snakes = len(game_data['board']['snakes'])

  def end_game(self, game_data:dict):
    self._set_winner_snake_name(game_data['board']['snakes'])
    self.get_type_of_game()

  # Function get Called from Server
  def snake_neat_make_a_move(self):
    move = self.snake_class.choose_move(self)

    self.turns.append({
      "turn": self.turn,
      "move": move,
      "game_board": self.get_game_board_as_dict()
    })

    return move

  # Save functions
  def _get_game_url(self, local_game:bool):
    if local_game:
      return None
    return f"https://play.battlesnake.com/game/{self.id}"

  def _set_winner_snake_name(self, snakes:list[dict]):
    if self.my_snake["id"] in [ x["id"] for x in snakes]:
      self.winner_snake_names = ["me"]
    else:
      self.winner_snake_names = [ x["name"] for x in snakes]
      if len(self.winner_snake_names) == 0:
        self.winner_snake_names = None

  def get_winner(self):
    return self.winner_snake_names

  def get_type_of_game(self):
    if self.init_snakes == 2:
      return {"name": "duel", "is_ladder": self.is_ladder}

    return {"name": self.type, "is_ladder": self.is_ladder}

  async def save(self, store_class, **kwargs):
    store = store_class(**kwargs)
    await store.save(self)
    del store
