#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "game.h"
#include "transition.h"
#include "input.h"
#include "log.h"
#include "util.h"
#include "word.h"
#include "flag.h"
#include "predicate.h"
#include "action.h"
#include "parse.h"

Game *game_create(void) {
  Game *g = malloc(sizeof(Game));
  g->should_close = false;

  g->rooms = malloc(sizeof(Rooms));
  g->rooms->count = 0;

  g->transitions = malloc(sizeof(Transitions));
  g->transitions->count = 0;

  Log *log = create_log();
  g->log = log;

  Vector2 input_position = { 20, 400 };
  Input *input = create_input(input_position);
  input->log = log;
  log->input = input;
  input->g = g;
  input->command = '>'; // Don't change this

  g->input = input;

  g->words = malloc(sizeof(Words));
  g->words->count = 0;

  g->flags = malloc(sizeof(Flags));
  g->flags->count = 0;

  g->actions = malloc(sizeof(Actions));
  g->actions->count = 0;

  return g;
}

void free_game(Game *g) {
  free_rooms(*g->rooms);
  free_input(g->input);
  free_log(g->log);
  free(g);
}

bool string_in(const char *input, ...) {
  va_list argp;
  va_start(argp, input);
  char *candidate;
  while ((candidate = va_arg(argp, char*))) {
    if (strcmp(input, candidate) == 0) {
      va_end(argp);
      return true;
    }
  }

  return false;
}

CommandType command_from_string(const char *string) {
  if (string_in(string, "QUIT", "Q", "EXIT", "CLOSE", NULL)) {
    return COMMAND_QUIT;
  }
  if (string_in(string, "LOOK", "L", NULL)) {
    return COMMAND_LOOK;
  }
  if (string_in(string, "NORTH", "N", NULL)) {
    return COMMAND_NORTH;
  }
  if (string_in(string, "SOUTH", "S", NULL)) {
    return COMMAND_SOUTH;
  }
  if (string_in(string, "EAST", "E", NULL)) {
    return COMMAND_EAST;
  }
  if (string_in(string, "WEST", "W", NULL)) {
    return COMMAND_WEST;
  }

  return COMMAND_UNKNOWN;
}

#define INVALID_DIRECTIONAL_COMMAND "I can't go %s from here"
void game_handle_directional_command(Game *g, const char *c) {
  Room *r = g->current_room;
  Transition *transition = find_transition(g->transitions, r, command_from_string(c));

  if (transition) {
    push_line_to_log(g->input->log, transition->description);
    g->current_room = transition->to;
  } else {
    char *response = malloc(strlen(INVALID_DIRECTIONAL_COMMAND) + strlen(c) + 1);
    sprintf(response, INVALID_DIRECTIONAL_COMMAND, c);
    push_line_to_log(g->input->log, response);
    free(response);
  }
}

#define INVALID_COMMAND "I don't know how to %s"
void game_handle_command(Game *g, const char *command) {
  Action *a = find_action(g, command);
  if (a) {

    if (strcmp(a->description, "*") != 0) push_line_to_log(g->input->log, a->description);
    for (int i = 0; i < a->effects_count; i++) {
      cause_effect(g, a->effects[i]);
    }
  } else {
    char *response = malloc(strlen(INVALID_COMMAND) + strlen(command) + 1);
    sprintf(response, INVALID_COMMAND, command);
    push_line_to_log(g->input->log, response);
    free(response);
  }
  return;

  Input *input = g->input;

  switch (command_from_string(command)) {
  case COMMAND_QUIT:
    g->should_close = true;
    break;
  case COMMAND_LOOK:
    push_line_to_log(input->log, g->current_room->description);
    break;
  case COMMAND_NORTH:
  case COMMAND_SOUTH:
  case COMMAND_EAST:
  case COMMAND_WEST:
    game_handle_directional_command(g, command);
    break;
  default:
    char *response = malloc(strlen(INVALID_COMMAND) + strlen(command) + 1);
    sprintf(response, INVALID_COMMAND, command);
    push_line_to_log(input->log, response);
    free(response);
    break;
  }
}

void game_handle_input(Game *g) {
  handle_pressed_keys(g->input);
}

void game_draw(Game *g) {
  BeginDrawing();
  ClearBackground(BLACK);
  draw_log(g->log);
  draw_text(g->input);
  EndDrawing();
}

void game_run_until_close(Game *g) {
  while (!WindowShouldClose() && !g->should_close)
    {
      game_handle_input(g);
      game_draw(g);
    }
}