/**
 * config.cpp:
 * parses the config... lol
 **/
#include "core/config.h"
#include "core/strings.h"
#include "core/anime.h"
#include "core/ini.h"
#include "core/filesystem.h"
#include "core/json.h"
#include "gui/translate/anime.h"
#include "gui/translate/config.h"

#include "animia/player.h"

#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <limits.h>

#include <QFile>
#include <QTextStream>

#include <iostream>

/* I'll use an INI-based config file instead of using an
 * XML file like Taiga.
 *
 * It technically isn't to spec, because I'm making these case-sensitive.
 * Boohoo.
*/

int Config::Load() {
	std::filesystem::path cfg_path = Filesystem::GetConfigPath();

	mINI::INIFile file(cfg_path.u8string());
	mINI::INIStructure ini;
	file.read(ini);

	service = Translate::ToService(INI::GetIniValue<std::string>(ini, "General", "Service", "None"));

	anime_list.score_format = Translate::ToScoreFormat(INI::GetIniValue<std::string>(ini, "Anime List", "Score format", "POINT_100"));
	anime_list.language = Translate::ToLanguage(INI::GetIniValue<std::string>(ini, "Anime List", "Title language", "Romaji"));
	anime_list.display_aired_episodes = INI::GetIniValue<bool>(ini, "Anime List", "Display only aired episodes", true);
	anime_list.display_available_episodes = INI::GetIniValue<bool>(ini, "Anime List", "Display only available episodes in library", true);
	anime_list.highlight_anime_if_available = INI::GetIniValue<bool>(ini, "Anime List", "Highlight anime if available", true);

	if (anime_list.highlight_anime_if_available) // sanity check
		anime_list.highlighted_anime_above_others = INI::GetIniValue<bool>(ini, "Anime List", "Display highlighted anime above others", false);
	else
		anime_list.highlighted_anime_above_others = false;

	auth.anilist.auth_token = INI::GetIniValue<std::string>(ini, "Authentication/AniList", "Auth Token", "");
	auth.anilist.user_id = INI::GetIniValue<int>(ini, "Authentication/AniList", "User ID", 0);

	torrents.feed_link = INI::GetIniValue<std::string>(ini, "Torrents", "RSS feed", "https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0");

	recognition.detect_media_players = INI::GetIniValue<bool>(ini, "Recognition", "Detect media players", true);

	/* lots of dumb logic to import the player data */
	{
		/* load the player data */
		QFile f(":/players.anisthesia");
		if (!f.exists())
			return false;

		f.open(QFile::ReadOnly | QFile::Text);
		QTextStream ts(&f);

		std::vector<animia::Player> players;

		if (!animia::ParsePlayersData(Strings::ToUtf8String(ts.readAll()), players))
			return false;

		recognition.players.reserve(players.size());
		for (const auto& player : players)
			recognition.players.push_back({true, player});
	}

	for (auto& [enabled, player] : recognition.players) {
		switch (player.type) {
			default:
			case animia::PlayerType::Default:
				enabled = INI::GetIniValue<bool>(ini, "Recognition/Players", player.name, true);
				break;
			case animia::PlayerType::WebBrowser:
				enabled = INI::GetIniValue<bool>(ini, "Recognition/Browsers", player.name, true);
				break;
		}
	}

	locale.RefreshAvailableLocales();
	locale.SetActiveLocale(QLocale(Strings::ToQString(INI::GetIniValue<std::string>(ini, "General", "Locale", "en_US"))));

	theme.SetTheme(Translate::ToTheme(INI::GetIniValue<std::string>(ini, "Appearance", "Theme", "Default")));

	{
		std::vector<std::string> v = Strings::Split(INI::GetIniValue<std::string>(ini, "Library", "Folders", ""), ";");
		for (const auto& s : v)
			if (!library.paths.count(s))
				library.paths.insert(s);
	}

	library.real_time_monitor = INI::GetIniValue<bool>(ini, "Library", "Real-time monitor", true);

	return 0;
}

int Config::Save() {
	std::filesystem::path cfg_path = Filesystem::GetConfigPath();
	Filesystem::CreateDirectories(cfg_path);

	mINI::INIFile file(cfg_path.string());
	mINI::INIStructure ini;

	INI::SetIniValue(ini, "General", "Service", service);
	INI::SetIniValue(ini, "General", "Locale", locale.GetLocale().name());

	INI::SetIniValue(ini, "Anime List", "Score format", Translate::ToString(anime_list.score_format));
	INI::SetIniValue(ini, "Anime List", "Title language", anime_list.language);
	INI::SetIniValue(ini, "Anime List", "Display only aired episodes", anime_list.display_aired_episodes);
	INI::SetIniValue(ini, "Anime List", "Display only available episodes in library", anime_list.display_available_episodes);
	INI::SetIniValue(ini, "Anime List", "Highlight anime if available", anime_list.highlight_anime_if_available);
	INI::SetIniValue(ini, "Anime List", "Display highlighted anime above others", anime_list.highlighted_anime_above_others);

	INI::SetIniValue(ini, "Authentication/AniList", "Auth Token", auth.anilist.auth_token);
	INI::SetIniValue(ini, "Authentication/AniList", "User ID", auth.anilist.user_id);

	INI::SetIniValue(ini, "Appearance", "Theme", theme.GetTheme());

	INI::SetIniValue(ini, "Torrents", "RSS feed", torrents.feed_link);

	INI::SetIniValue(ini, "Recognition", "Detect media players", recognition.detect_media_players);

	for (const auto& [enabled, player] : recognition.players) {
		switch (player.type) {
			default:
			case animia::PlayerType::Default:
				INI::SetIniValue(ini, "Recognition/Players", player.name, enabled);
				break;
			case animia::PlayerType::WebBrowser:
				INI::SetIniValue(ini, "Recognition/Browsers", player.name, enabled);
				break;
		}
	}

	INI::SetIniValue(ini, "Library", "Folders", Strings::Implode(library.paths, ";"));
	INI::SetIniValue(ini, "Library", "Real-time monitor", library.real_time_monitor);

	file.write(ini);

	return 0;
}
