#include "episode.h"
#include "stringutils.h"
#include <stdio.h>
#include <string.h>

static int string_find(const char *str, int len, int offset, char char_to_find) {
    for(int i = offset; i < len; ++i) {
        if(str[i] == char_to_find)
            return i;
    }
    return -1;
}

static int string_rfind(const char *str, int len, int offset, char char_to_find) {
    for(int i = offset - 1; i >= 0; --i) {
        if(str[i] == char_to_find)
            return i + (len - offset);
    }
    return -1;
}

int episode_info_create_from_episode_name(EpisodeInfo *self, const char *episode_name) {
    self->episode_name[0] = '\0';
    self->group_name = NULL;
    self->anime_name = NULL;
    self->episode = NULL;
    self->resolution = NULL;
    self->extension = NULL;

    int episode_name_len = strlen(episode_name);
    if(episode_name_len > 500) {
        fprintf(stderr, "Episode name is too long! it can't be more than 500 characters\n");
        return -1;
    }

    char episode_name_s[512];
    strcpy(episode_name_s, episode_name);
    char *episode_name_stripped = strip(episode_name_s);
    int episode_name_stripped_len = strlen(episode_name_stripped);
    int episode_name_offset = 0;

    if(episode_name_stripped_len == 0)
        return -1;

    int extension_index = string_rfind(episode_name_stripped, episode_name_stripped_len, episode_name_stripped_len, '.');
    if(extension_index != -1) {
        int extension_len = episode_name_stripped_len - extension_index;
        self->extension = self->episode_name + episode_name_offset;
        memcpy(self->extension, episode_name_stripped + extension_index, extension_len);
        self->extension[extension_len] = '\0';
        episode_name_offset += extension_len + 1;
        episode_name_stripped_len = extension_index;
    }

    if(episode_name_stripped[0] != '[')
        return -1;

    int group_name_end = string_find(episode_name_stripped, episode_name_stripped_len, 0, ']');
    if(group_name_end == -1)
        return -1;

    int group_name_len = group_name_end - 1;
    self->group_name = self->episode_name + episode_name_offset;
    memcpy(self->group_name, episode_name_stripped + 1, group_name_len);
    self->group_name[group_name_len] = '\0';
    self->group_name = strip(self->group_name);
    episode_name_offset += group_name_len + 1;

    int last_dash = string_rfind(episode_name_stripped, episode_name_stripped_len, episode_name_stripped_len, '-');
    if(last_dash == -1)
        return -1;

    int anime_name_len = last_dash - 1 - group_name_end;
    self->anime_name = self->episode_name + episode_name_offset;
    memcpy(self->anime_name, episode_name_stripped + group_name_end + 1, anime_name_len);
    self->anime_name[anime_name_len] = '\0';
    self->anime_name = strip(self->anime_name);
    episode_name_offset += anime_name_len + 1;

    int resolution_index_bracket = string_find(episode_name_stripped, episode_name_stripped_len, last_dash + 1, '[');
    int resolution_index_parentheses = string_find(episode_name_stripped, episode_name_stripped_len, last_dash + 1, '(');
    char resolution_end_char = ']';
    int resolution_index = resolution_index_bracket;
    self->resolution_in_brackets = 1;
    if(resolution_index_parentheses != -1 && resolution_index_parentheses < resolution_index_bracket) {
        resolution_index = resolution_index_parentheses;
        resolution_end_char = ')';
        self->resolution_in_brackets = 0;
    }
    if(resolution_index == -1) {
        /* TODO: Test if this works */
        int episode_len = episode_name_stripped_len - (last_dash + 1);
        self->episode = self->episode_name + episode_name_offset;
        memcpy(self->episode, episode_name_stripped + last_dash + 1, episode_len);
        self->episode[episode_len] = '\0';
        self->episode = strip(self->episode);
    } else {
        int episode_len = resolution_index - (last_dash + 1);
        self->episode = self->episode_name + episode_name_offset;
        memcpy(self->episode, episode_name_stripped + last_dash + 1, episode_len);
        self->episode[episode_len] = '\0';
        self->episode = strip(self->episode);
        episode_name_offset += episode_len + 1;

        int resolution_end = string_find(episode_name_stripped, episode_name_stripped_len, resolution_index + 1, resolution_end_char);
        if(resolution_end != -1) {
            int resolution_len = resolution_end - (resolution_index + 1);
            if(resolution_len != 8 && episode_name_stripped[resolution_end - 1] == 'p') { // resolution_len is 8 when [] is a CRC and not resolution
                self->resolution = self->episode_name + episode_name_offset;
                memcpy(self->resolution, episode_name_stripped + resolution_index + 1, resolution_len);
                self->resolution[resolution_len] = '\0';
                self->resolution = strip(self->resolution);
            }
        }
    }
    
    return 0;
}

int episode_info_get_generic_name(EpisodeInfo *self, char *output_buffer, int output_buffer_size) {
    if(!self->group_name || !self->anime_name)
        return -1;
    
    int bytes_written = 0;
    if(self->resolution) {
        char res_start_symbol = (self->resolution_in_brackets ? '[' : '(');
        char res_end_symbol = (self->resolution_in_brackets ? ']' : ')');
        if(self->extension)
            bytes_written = snprintf(output_buffer, output_buffer_size, "[%s] %s %c%s%c%s", self->group_name, self->anime_name, res_start_symbol, self->resolution, res_end_symbol, self->extension);
        else
            bytes_written = snprintf(output_buffer, output_buffer_size, "[%s] %s %c%s%c", self->group_name, self->anime_name, res_start_symbol, self->resolution, res_end_symbol);
    } else {
        if(self->extension)
            bytes_written = snprintf(output_buffer, output_buffer_size, "[%s] %s%s", self->group_name, self->anime_name, self->extension);
        else
            bytes_written = snprintf(output_buffer, output_buffer_size, "[%s] %s", self->group_name, self->anime_name);
    }
    
    if(bytes_written >= output_buffer_size) {
        fprintf(stderr, "Failed to write generic name to buffer\n");
        return -1;
    }

    return 0;
}