#include "cheevos.h"
#include <SDL2/SDL_error.h>  // for SDL_GetError
#include <SDL2/SDL_rwops.h>  // for SDL_RWFromFile, SDL_RWclose, SDL_RWwrite
#include <stddef.h>          // for NULL
#include <iostream>          // for basic_ostream, operator<<, cout, endl
#include "screen.h"          // for Screen
#include "utils.h"           // for options_t

// Constructor
Cheevos::Cheevos(Screen *screen, options_t *options, std::string file)
{
    // Copia la dirección de los objetos
    this->options = options;
    this->screen = screen;
    this->file = file;

    // Inicializa los logros
    init();

    // Inicializa variables
    enabled = true;

    // Carga el estado de los logros
    load();
}

// Destructor
Cheevos::~Cheevos()
{
    // Guarda el estado de los logros
    save();

    cheevos.clear();
}

// Inicializa los logros
void Cheevos::init()
{
    cheevos.clear();

    cheevos_t c;
    c.completed = false;
    c.valid = true;
    c.icon = 2;

    c.id = 1;
    c.caption = "SHINY THINGS";
    c.description = "Get 25\% of the items";
    cheevos.push_back(c);

    c.id = 2;
    c.caption = "HALF THE WORK";
    c.description = "Get 50\% of the items";
    cheevos.push_back(c);

    c.id = 3;
    c.caption = "GETTING THERE";
    c.description = "Get 75\% of the items";
    cheevos.push_back(c);

    c.id = 4;
    c.caption = "THE COLLECTOR";
    c.description = "Get 100\% of the items";
    cheevos.push_back(c);

    c.id = 5;
    c.caption = "WANDERING AROUND";
    c.description = "Visit 20 rooms";
    cheevos.push_back(c);

    c.id = 6;
    c.caption = "I GOT LOST";
    c.description = "Visit 40 rooms";
    cheevos.push_back(c);

    c.id = 7;
    c.caption = "I LIKE TO EXPLORE";
    c.description = "Visit all rooms";
    cheevos.push_back(c);

    c.id = 8;
    c.caption = "FINISH THE GAME";
    c.description = "Complete the game";
    cheevos.push_back(c);

    c.id = 9;
    c.caption = "I WAS SUCKED BY A HOLE";
    c.description = "Complete the game without entering the jail";
    cheevos.push_back(c);

    c.id = 10;
    c.caption = "MY LITTLE PROJECTS";
    c.description = "Complete the game with all items";
    cheevos.push_back(c);

    c.id = 11;
    c.caption = "I LIKE MY MULTICOLOURED FRIENDS";
    c.description = "Complete the game without dying";
    cheevos.push_back(c);

    c.id = 12;
    c.caption = "SHIT PROJECTS DONE FAST";
    c.description = "Complete the game in under 30 minutes";
    cheevos.push_back(c);
}

// Busca un logro por id y devuelve el indice
int Cheevos::find(int id)
{
    for (int i = 0; i < (int)cheevos.size(); ++i)
    {
        if (cheevos[i].id == id)
        {
            return i;
        }
    }

    return -1;
}

// Desbloquea un logro
void Cheevos::unlock(int id)
{
    const int index = find(id);

    if (index == -1)
    {
        return;
    }

    if (!cheevos[index].valid)
    {
        return;
    }

    if (cheevos[index].completed)
    {
        return;
    }

    if (!enabled)
    {
        return;
    }

    cheevos[index].completed = true;
    screen->showNotification("ACHIEVEMENT UNLOCKED!", cheevos[index].caption, cheevos[index].icon);
    save();
}

// Invalida un logro
void Cheevos::invalidate(int id)
{
    const int index = find(id);
    if (index == -1)
    {
        return;
    }
    cheevos[index].valid = false;
}

// Habilita o deshabilita los logros
void Cheevos::enable(bool value)
{
    enabled = value;
}

// Carga el estado de los logros
void Cheevos::load()
{
    // Carga el estado de los logros desde un fichero
    loadFromFile();
}

// Guarda el estado de los logros
void Cheevos::save()
{
    // Guarda el estado de los logros en un fichero
    saveToFile();
}

// Carga el estado de los logros desde un fichero
void Cheevos::loadFromFile()
{
    // Abre el fichero en modo lectura (binario)
    SDL_RWops *file = SDL_RWFromFile(this->file.c_str(), "r+b");

    // El fichero no existe
    if (file == NULL)
    {
        if (options->console)
        {
            std::cout << "Warning: Unable to open file! SDL Error: " << SDL_GetError() << std::endl;
        }

        // Crea el fichero en modo escritura (binario)
        file = SDL_RWFromFile(this->file.c_str(), "w+b");

        if (file != NULL)
        {
            if (options->console)
            {
                std::cout << "New file created!" << std::endl;
            }

            // Guarda la información
            for (int i = 0; i < (int)cheevos.size(); ++i)
            {
                SDL_RWwrite(file, &cheevos[i].completed, sizeof(bool), 1);
            }

            // Cierra el fichero
            SDL_RWclose(file);
        }
        else
        {
            if (options->console)
            {
                std::cout << "Error: Unable to create file! SDL Error: " << SDL_GetError() << std::endl;
            }
        }
    }
    // El fichero existe
    else
    {
        // Carga los datos
        if (options->console)
        {
            std::cout << "Reading file...!" << std::endl;
        }
        for (int i = 0; i < (int)cheevos.size(); ++i)
        {
            SDL_RWread(file, &cheevos[i].completed, sizeof(bool), 1);
        }

        // Cierra el fichero
        SDL_RWclose(file);
    }
}

// Guarda el estado de los logros en un fichero
void Cheevos::saveToFile()
{
    // Abre el fichero en modo escritura (binario)
    SDL_RWops *file = SDL_RWFromFile(this->file.c_str(), "w+b");
    if (file != NULL)
    {
        // Guarda la información
        for (int i = 0; i < (int)cheevos.size(); ++i)
        {
            SDL_RWwrite(file, &cheevos[i].completed, sizeof(bool), 1);
        }

        // Cierra el fichero
        SDL_RWclose(file);
    }
    else
    {
        if (options->console)
        {
            std::cout << "Error: Unable to save file! " << SDL_GetError() << std::endl;
        }
    }
}

// Lista los logros
std::vector<cheevos_t> Cheevos::list()
{
    return cheevos;
}

// Devuelve el número total de logros desbloqueados
int Cheevos::unlocked()
{
    int count = 0;
    for (auto cheevo : cheevos)
    {
        if (cheevo.completed)
            count++;
    }
    return count;
}

// Devuelve el número total de logros
int Cheevos::count()
{
    return cheevos.size();
}

// Vuelve a cargar los logros desde el origen
void Cheevos::reload()
{
    load();
}