#ifndef __core__anime_h
#define __core__anime_h
#include "core/date.h"
#include <array>
#include <map>
#include <vector>

namespace Anime {

enum class ListStatus {
	NOT_IN_LIST,
	CURRENT,
	COMPLETED,
	PAUSED,
	DROPPED,
	PLANNING
};

constexpr std::array<ListStatus, 5> ListStatuses{ListStatus::CURRENT, ListStatus::COMPLETED, ListStatus::PAUSED,
                                                 ListStatus::DROPPED, ListStatus::PLANNING};

enum class SeriesStatus {
	UNKNOWN,
	FINISHED,
	RELEASING,
	NOT_YET_RELEASED,
	CANCELLED,
	HIATUS
};

enum class SeriesFormat {
	UNKNOWN,
	TV,
	TV_SHORT,
	MOVIE,
	SPECIAL,
	OVA,
	ONA,
	MUSIC,
	MANGA,
	NOVEL,
	ONE_SHOT
};

enum class SeriesSeason {
	UNKNOWN,
	WINTER,
	SPRING,
	SUMMER,
	FALL
};

enum class TitleLanguage {
	ROMAJI,
	NATIVE,
	ENGLISH
};

enum class Services {
	NONE,
	ANILIST,
	NB_SERVICES
};

enum class ScoreFormat {
	POINT_100, // 0-100
	POINT_10_DECIMAL, // 0.0-10.0
	POINT_10, // 0-10
	POINT_5, // 0-5, should be represented in stars
	POINT_3 // 1-3, should be represented in smileys
};

constexpr std::array<ScoreFormat, 5> ScoreFormats{ScoreFormat::POINT_100, ScoreFormat::POINT_10_DECIMAL, ScoreFormat::POINT_10,
                                                  ScoreFormat::POINT_5,   ScoreFormat::POINT_3};

struct ListInformation {
		int id = 0;
		int progress = 0;
		int score = 0; // note that this will ALWAYS be in POINT_100 format and must be converted
		ListStatus status = ListStatus::NOT_IN_LIST;
		Date started;
		Date completed;
		bool is_private = false;
		unsigned int rewatched_times = 0;
		bool rewatching = false;
		uint64_t updated = 0;
		std::string notes;
};

struct SeriesInformation {
		int id;
		struct {
				std::string romaji;
				std::string english;
				std::string native;
		} title;
		std::vector<std::string> synonyms;
		int episodes = 0;
		SeriesStatus status = SeriesStatus::UNKNOWN;
		Date air_date;
		std::vector<std::string> genres;
		std::vector<std::string> producers;
		SeriesFormat format = SeriesFormat::UNKNOWN;
		SeriesSeason season = SeriesSeason::UNKNOWN;
		int audience_score = 0;
		std::string synopsis;
		int duration = 0;
		std::string poster_url;
};

class Anime {
	public:
		/* User list data */
		ListStatus GetUserStatus() const;
		int GetUserProgress() const;
		int GetUserScore() const;
		std::string GetUserPresentableScore() const;
		Date GetUserDateStarted() const;
		Date GetUserDateCompleted() const;
		bool GetUserIsPrivate() const;
		unsigned int GetUserRewatchedTimes() const;
		bool GetUserIsRewatching() const;
		uint64_t GetUserTimeUpdated() const;
		std::string GetUserNotes() const;

		void SetUserStatus(ListStatus status);
		void SetUserScore(int score);
		void SetUserProgress(int progress);
		void SetUserDateStarted(Date const& started);
		void SetUserDateCompleted(Date const& completed);
		void SetUserIsPrivate(bool is_private);
		void SetUserRewatchedTimes(int rewatched);
		void SetUserIsRewatching(bool rewatching);
		void SetUserTimeUpdated(uint64_t updated);
		void SetUserNotes(std::string const& notes);

		/* Series data */
		int GetId() const;
		std::string GetRomajiTitle() const;
		std::string GetEnglishTitle() const;
		std::string GetNativeTitle() const;
		std::vector<std::string> GetTitleSynonyms() const;
		int GetEpisodes() const;
		SeriesStatus GetAiringStatus() const;
		Date GetAirDate() const;
		std::vector<std::string> GetGenres() const;
		std::vector<std::string> GetProducers() const;
		SeriesFormat GetFormat() const;
		SeriesSeason GetSeason() const;
		int GetAudienceScore() const;
		std::string GetSynopsis() const;
		int GetDuration() const;
		std::string GetPosterUrl() const;
		std::string GetServiceUrl() const;

		void SetId(int id);
		void SetRomajiTitle(std::string const& title);
		void SetEnglishTitle(std::string const& title);
		void SetNativeTitle(std::string const& title);
		void SetTitleSynonyms(std::vector<std::string> const& synonyms);
		void AddTitleSynonym(std::string const& synonym);
		void SetEpisodes(int episodes);
		void SetAiringStatus(SeriesStatus status);
		void SetAirDate(Date const& date);
		void SetGenres(std::vector<std::string> const& genres);
		void SetProducers(std::vector<std::string> const& producers);
		void SetFormat(SeriesFormat format);
		void SetSeason(SeriesSeason season);
		void SetAudienceScore(int audience_score);
		void SetSynopsis(std::string synopsis);
		void SetDuration(int duration);
		void SetPosterUrl(std::string poster);

		std::string GetUserPreferredTitle() const;

		/* User stuff */
		void AddToUserList();
		bool IsInUserList() const;
		void RemoveFromUserList();

	private:
		SeriesInformation info_;
		std::shared_ptr<struct ListInformation> list_info_;
};

} // namespace Anime

#endif // __core__anime_h
