#define SHINEY_PROB 32

#include <stdlib.h>
#include <argp.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <regex.h>

const char *argp_program_version =
  "pkmn 1.0";
const char *argp_program_bug_address =
  "<gauvain.thomas@gmail.com>";

/* Program documentation. */
static char doc[] =
  "Argp example #3 -- a program with options and arguments using argp";

/* A description of the arguments we accept. */
static char args_doc[] = "pokemon_name";

/* The options we understand. */
static struct argp_option options[] = {
  {"random",   'r', 0,      0,  "Use a random pokemon"},
  {"shiney",   's', 0,      0,  "Use a shiney pokemon"},
  {"verbose",  'v', 0,      0,  "Produce verbose output" },
  { 0 }
};

/* Used by main to communicate with parse_opt. */
struct arguments
{
  char *args[1];                /* arg*/
  int silent, verbose;
  int random, shiney;          /* random and shiney flags */ 
};

/* Parse a single option. */
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
  /* Get the input argument from argp_parse, which we
     know is a pointer to our arguments structure. */
  struct arguments *arguments = state->input;

  switch (key)
    {
    case 'v':
      arguments->verbose = 1;
      break;
    case 'r':
      arguments->random = 1;
      break;
    case 's':
      arguments->shiney = 1;
      break;

    case ARGP_KEY_ARG:
      if (state->arg_num >= 1)
        /* Too many arguments. */
        argp_usage (state);

      arguments->args[state->arg_num] = arg;

      break;

    case ARGP_KEY_END:
      if (state->arg_num < 1 && !arguments->random)
        /* Not enough arguments. */
        argp_usage (state);
      break;

    default:
      return ARGP_ERR_UNKNOWN;
    }
  return 0;
}

/* Our argp parser. */
static struct argp argp = { options, parse_opt, args_doc, doc };


int pkmn_name_from_file(char *pokemon_file, char *pokemon_name) {

  int BUFFER_SIZE = 512;

  // A file is of the form "[S_][0-9][0-9][0-9]_pokemon.cow"
  // We want to write the pokemon name in pokemon_name
  // Using regex: s/^[S_]*[0-9]*_//g
  // char *pokemon_file = "843_silicobra.cow";
  char regex_pattern[] = "^S?_?[0-9]+_(([a-zA-Z-])+)\\.cow$"; // Regex pattern to match the Pokémon name
  regex_t regex;
  regmatch_t matches[100];
  char match_buffer[BUFFER_SIZE];
  int ret;

  // Compile the regular expression
  ret = regcomp(&regex, regex_pattern, REG_EXTENDED);
  if (ret != 0) {
      fprintf(stderr, "Failed to compile regex\n");
      return 1;
  }

  // Execute the regular expression
  ret = regexec(&regex, pokemon_file, 100, matches, 0);
  if (ret == 0) {
    // Extract the matched substring
    int start = matches[1].rm_so;
    int end = matches[1].rm_eo;
    int match_length = end - start;
    if (match_length < BUFFER_SIZE - 1) {
      strncpy(match_buffer, pokemon_file + start, match_length);
      match_buffer[match_length] = '\0';
      strcpy(pokemon_name, match_buffer);
    } else {
      fprintf(stderr, "Match too long for buffer\n");
    }
} else if (ret == REG_NOMATCH) {
  fprintf(stderr, "No match found\n");
} else {
  fprintf(stderr, "Regex match failed\n");
  }

  // Free the regex memory
  regfree(&regex);

  return 0;
}

int get_pokemon_file(char *arg, char *pokemon_file) {
  // Finds a matching file in the pokemons directory from the argument
  // Returns 0 if the file was found, 1 otherwise
  // ls ~/pokemons/yes | fzf -f wp | head -1
  char command[512];
  sprintf(command, "ls ~/pokemons/yes | fzf -f %s | head -1 > /tmp/pkmn", arg);
  system(command);
  FILE *f = fopen("/tmp/pkmn", "r");
  fscanf(f, "%s", pokemon_file);
  fclose(f);

  if (strlen(pokemon_file) == 0) {
    return 1;
  }
  return 0;
}

int main (int argc, char **argv) {
  struct arguments arguments;
  char pkmn_path[] = "~/pokemons/";

  /* Default values. */
  arguments.verbose = 0;
  arguments.random = 0;
  arguments.shiney = 0;

  // A pokemon has a 1/SHINEY_PROB chance of being shiney
  srand(time(NULL));
  arguments.shiney = (rand() % SHINEY_PROB) == 0;

  /* Parse our arguments; every option seen by parse_opt will
      be reflected in arguments. */
  argp_parse (&argp, argc, argv, 0, 0, &arguments);

  if (arguments.verbose) {
    printf("ARG1 = %s\n", arguments.args[0]);
    printf("VERBOSE = %s\n", arguments.verbose ? "yes" : "no");
    printf("RANDOM = %s\n", arguments.random ? "yes" : "no");
    printf("SHINEY = %s\n", arguments.shiney ? "yes" : "no");
  }

  char pokemon_file[512];
  if (arguments.random) {
    system("ls ~/pokemons/yes | shuf -n 1 > /tmp/pkmn");
    FILE *f = fopen("/tmp/pkmn", "r");
    fscanf(f, "%s", pokemon_file);
    fclose(f);
    if (arguments.verbose) {
      printf("Random pokemon: %s\n", pokemon_file);
    }
  } else {
    if (get_pokemon_file(arguments.args[0], pokemon_file) == 1) {
      fprintf(stderr, "No matching pokemon found\n");
      exit(EXIT_FAILURE);
    }
  }

  if (arguments.shiney) {
    // Append "S_" at the beginning of the file
    char tmp[512];
    sprintf(tmp, "S_%s", pokemon_file);
    sprintf(pokemon_file, "%s", tmp);
    if (arguments.verbose) {
      printf("Shiney pokemon: %s\n", pokemon_file);
    }
  }

  // Extract the pokemon name from the file
  char pokemon_name[512];
  pkmn_name_from_file(pokemon_file, pokemon_name);
  pokemon_name[0] = toupper(pokemon_name[0]);
  if (arguments.verbose) {
    printf("Pokemon file: %s\n", pokemon_file);
    printf("Pokemon name: %s\n", pokemon_name);
  }

  // Execute the command echo "$pokemon_name!" | cowsay -f "$cow_file" -W 70
  char command[1024];
  if (arguments.shiney) {
    sprintf(command, "echo \"Shiny %s!\" | cowsay -f %s%s -W 70", pokemon_name, pkmn_path, pokemon_file);
  } else {
    sprintf(command, "echo \"%s!\" | cowsay -f %syes/%s -W 70", pokemon_name, pkmn_path, pokemon_file);
  }
  system(command);


  exit(EXIT_SUCCESS);
}