#include "core/anime.h"
#include "core/strings.h"
#include "gui/translate/anime.h"

#include <QCoreApplication>

#include <unordered_map>

#include <fmt/core.h>

namespace Translate {

std::string ToString(const Anime::ListStatus status)
{
	switch (status) {
		case Anime::ListStatus::Current: return "Currently watching";
		case Anime::ListStatus::Planning: return "Plan to watch";
		case Anime::ListStatus::Completed: return "Completed";
		case Anime::ListStatus::Dropped: return "Dropped";
		case Anime::ListStatus::Paused: return "On hold";
		default:
		case Anime::ListStatus::NotInList: return "Not in list";
	}
}

std::string ToString(const Anime::SeriesFormat format)
{
	switch (format) {
		case Anime::SeriesFormat::Tv: return "TV";
		case Anime::SeriesFormat::TvShort: return "TV short";
		case Anime::SeriesFormat::Ova: return "OVA";
		case Anime::SeriesFormat::Movie: return "Movie";
		case Anime::SeriesFormat::Special: return "Special";
		case Anime::SeriesFormat::Ona: return "ONA";
		case Anime::SeriesFormat::Music: return "Music";
		default:
		case Anime::SeriesFormat::Unknown: return "Unknown";
	}
}

std::string ToString(const Anime::Season::Name season)
{
	switch (season) {
		case Anime::Season::Name::Winter: return "Winter";
		case Anime::Season::Name::Summer: return "Summer";
		case Anime::Season::Name::Autumn: return "Autumn";
		case Anime::Season::Name::Spring: return "Spring";
		default:
		case Anime::Season::Name::Unknown: return "Unknown";
	}
}

std::string ToString(const Anime::SeriesStatus status)
{
	switch (status) {
		case Anime::SeriesStatus::Releasing: return "Currently airing";
		case Anime::SeriesStatus::Finished: return "Finished airing";
		case Anime::SeriesStatus::NotYetReleased: return "Not yet aired";
		case Anime::SeriesStatus::Cancelled: return "Cancelled";
		case Anime::SeriesStatus::Hiatus: return "On hiatus";
		default:
		case Anime::SeriesStatus::Unknown: return "Unknown";
	}
}

std::string ToString(const Anime::Service service)
{
	switch (service) {
		case Anime::Service::AniList: return "AniList";
		case Anime::Service::MyAnimeList: return "MyAnimeList";
		case Anime::Service::Kitsu: return "Kitsu";
		default:
		case Anime::Service::None: return "None";
	}
}

std::string ToString(const Anime::TitleLanguage language)
{
	switch (language) {
		case Anime::TitleLanguage::Native: return "Native";
		case Anime::TitleLanguage::English: return "English";
		default:
		case Anime::TitleLanguage::Romaji: return "Romaji";
	}
}

std::string ToString(const Anime::ScoreFormat format)
{
	switch (format) {
		case Anime::ScoreFormat::Point3: return "3-point";
		case Anime::ScoreFormat::Point5: return "5-point";
		case Anime::ScoreFormat::Point10: return "10-point";
		case Anime::ScoreFormat::Point10Decimal: return "10-point Decimal";
		default:
		case Anime::ScoreFormat::Point100: return "100-point";
	}
}

Anime::ListStatus ToListStatus(const std::string &str)
{
	static const std::unordered_map<std::string, Anime::ListStatus> map = {
	    {"currently watching", Anime::ListStatus::Current  },
	    {"plan to watch",      Anime::ListStatus::Planning },
	    {"completed",          Anime::ListStatus::Completed},
	    {"dropped",            Anime::ListStatus::Dropped  },
	    {"on hold",            Anime::ListStatus::Paused   }
    };

	std::string lower = Strings::ToLower(str);

	if (map.find(lower) == map.end())
		return Anime::ListStatus::NotInList;
	return map.at(lower);
}

Anime::SeriesStatus ToSeriesStatus(const std::string &str)
{
	static const std::unordered_map<std::string, Anime::SeriesStatus> map = {
	    {"currently airing", Anime::SeriesStatus::Releasing     },
	    {"finished airing",  Anime::SeriesStatus::Finished      },
	    {"not yet aired",    Anime::SeriesStatus::NotYetReleased},
	    {"cancelled",        Anime::SeriesStatus::Cancelled     },
	    {"on hiatus",        Anime::SeriesStatus::Hiatus        }
    };

	std::string lower = Strings::ToLower(str);

	if (map.find(str) == map.end())
		return Anime::SeriesStatus::Unknown;
	return map.at(str);
}

Anime::Season::Name ToSeriesSeason(const std::string &str)
{
	static const std::unordered_map<std::string, Anime::Season::Name> map = {
	    {"winter", Anime::Season::Name::Winter},
        {"summer", Anime::Season::Name::Summer},
	    {"fall",   Anime::Season::Name::Autumn},
        {"autumn", Anime::Season::Name::Autumn},
	    {"spring", Anime::Season::Name::Spring},
	};

	std::string lower = Strings::ToLower(str);

	if (map.find(lower) == map.end())
		return Anime::Season::Name::Unknown;
	return map.at(lower);
}

Anime::SeriesFormat ToSeriesFormat(const std::string &str)
{
	static const std::unordered_map<std::string, Anime::SeriesFormat> map = {
	    {"tv",       Anime::SeriesFormat::Tv     },
        {"tv short", Anime::SeriesFormat::TvShort},
	    {"ova",      Anime::SeriesFormat::Ova    },
        {"movie",    Anime::SeriesFormat::Movie  },
	    {"special",  Anime::SeriesFormat::Special},
        {"ona",      Anime::SeriesFormat::Ona    },
	    {"music",    Anime::SeriesFormat::Music  }
    };

	std::string lower = Strings::ToLower(str);

	if (map.find(lower) == map.end())
		return Anime::SeriesFormat::Unknown;
	return map.at(lower);
}

Anime::Service ToService(const std::string &str)
{
	static const std::unordered_map<std::string, Anime::Service> map = {
	    {"anilist",     Anime::Service::AniList    },
	    {"myanimelist", Anime::Service::MyAnimeList},
	    {"kitsu",       Anime::Service::Kitsu      }
    };

	std::string lower = Strings::ToLower(str);

	if (map.find(lower) == map.end())
		return Anime::Service::None;
	return map.at(lower);
}

Anime::TitleLanguage ToLanguage(const std::string &str)
{
	static const std::unordered_map<std::string, Anime::TitleLanguage> map = {
	    {"romaji",  Anime::TitleLanguage::Romaji },
	    {"native",  Anime::TitleLanguage::Native },
	    {"english", Anime::TitleLanguage::English}
    };

	std::string lower = Strings::ToLower(str);

	if (map.find(lower) == map.end())
		return Anime::TitleLanguage::Romaji;
	return map.at(lower);
}

Anime::ScoreFormat ToScoreFormat(const std::string &str)
{
	static const std::unordered_map<std::string, Anime::ScoreFormat> map = {
	    {"3-point",          Anime::ScoreFormat::Point3        },
	    {"5-point",          Anime::ScoreFormat::Point5        },
	    {"10-point",         Anime::ScoreFormat::Point10       },
	    {"10-point decimal", Anime::ScoreFormat::Point10Decimal},
	    {"100-point",        Anime::ScoreFormat::Point100      },
	    /* old values, provided for compatibility */
	    {"point_3",          Anime::ScoreFormat::Point3        },
	    {"point_5",          Anime::ScoreFormat::Point5        },
	    {"point_10",         Anime::ScoreFormat::Point10       },
	    {"point_10_decimal", Anime::ScoreFormat::Point10Decimal},
	    {"point_100",        Anime::ScoreFormat::Point100      },
	};

	std::string lower = Strings::ToLower(str);

	if (map.find(lower) == map.end())
		return Anime::ScoreFormat::Point100;
	return map.at(lower);
}

/* Localized versions of ToString() functions. Meant for display to the user. */

std::string ToLocalString(const Anime::ListStatus status)
{
	switch (status) {
		case Anime::ListStatus::Current: return Strings::Translate("Currently watching");
		case Anime::ListStatus::Planning: return Strings::Translate("Plan to watch");
		case Anime::ListStatus::Completed: return Strings::Translate("Completed");
		case Anime::ListStatus::Dropped: return Strings::Translate("Dropped");
		case Anime::ListStatus::Paused: return Strings::Translate("On hold");
		default:
		case Anime::ListStatus::NotInList: return Strings::Translate("Not in list");
	}
}

std::string ToLocalString(const Anime::SeriesFormat format)
{
	switch (format) {
		case Anime::SeriesFormat::Tv: return Strings::Translate("TV");
		case Anime::SeriesFormat::TvShort: return Strings::Translate("TV short");
		case Anime::SeriesFormat::Ova: return Strings::Translate("OVA");
		case Anime::SeriesFormat::Movie: return Strings::Translate("Movie");
		case Anime::SeriesFormat::Special: return Strings::Translate("Special");
		case Anime::SeriesFormat::Ona: return Strings::Translate("ONA");
		case Anime::SeriesFormat::Music: return Strings::Translate("Music");
		default:
		case Anime::SeriesFormat::Unknown: return Strings::Translate("Unknown");
	}
}

static std::string ToLocalString(const Anime::Season::Name season)
{
	switch (season) {
		case Anime::Season::Name::Winter: return Strings::Translate("Winter");
		case Anime::Season::Name::Summer: return Strings::Translate("Summer");
		case Anime::Season::Name::Autumn: return Strings::Translate("Autumn");
		case Anime::Season::Name::Spring: return Strings::Translate("Spring");
		default:
		case Anime::Season::Name::Unknown: return Strings::Translate("Unknown");
	}
}

std::string ToLocalString(const Anime::Season &season)
{
	std::string year = (season.year) ? Strings::ToUtf8String(season.year) : Strings::Translate("Unknown");

	return fmt::format(Strings::Translate("{} {}"), ToLocalString(season.season), year);
}

std::string ToLocalString(const Anime::SeriesStatus status)
{
	switch (status) {
		case Anime::SeriesStatus::Releasing: return Strings::Translate("Currently airing");
		case Anime::SeriesStatus::Finished: return Strings::Translate("Finished airing");
		case Anime::SeriesStatus::NotYetReleased: return Strings::Translate("Not yet aired");
		case Anime::SeriesStatus::Cancelled: return Strings::Translate("Cancelled");
		case Anime::SeriesStatus::Hiatus: return Strings::Translate("On hiatus");
		default:
		case Anime::SeriesStatus::Unknown: return Strings::Translate("Unknown");
	}
}

std::string ToLocalString(const Anime::Service service)
{
	switch (service) {
		case Anime::Service::AniList: return Strings::Translate("AniList");
		case Anime::Service::MyAnimeList: return Strings::Translate("MyAnimeList");
		case Anime::Service::Kitsu: return Strings::Translate("Kitsu");
		default:
		case Anime::Service::None: return Strings::Translate("None");
	}
}

std::string ToLocalString(const Anime::TitleLanguage language)
{
	switch (language) {
		case Anime::TitleLanguage::Native: return Strings::Translate("Native");
		case Anime::TitleLanguage::English: return Strings::Translate("English");
		default:
		case Anime::TitleLanguage::Romaji: return Strings::Translate("Romaji");
	}
}

std::string ToLocalString(const Anime::ScoreFormat format)
{
	switch (format) {
		case Anime::ScoreFormat::Point3: return Strings::Translate("3-point");
		case Anime::ScoreFormat::Point5: return Strings::Translate("5-point");
		case Anime::ScoreFormat::Point10: return Strings::Translate("10-point");
		case Anime::ScoreFormat::Point10Decimal: return Strings::Translate("10-point Decimal");
		default:
		case Anime::ScoreFormat::Point100: return Strings::Translate("100-point");
	}
}

} // namespace Translate
