#include "core/date.h"
#include "core/json.h"

#include <QDate>
#include <QDebug>

#include <algorithm>

/* An implementation of AniList's "fuzzy date" */

Date::Date() {
}

Date::Date(unsigned int y) {
	SetYear(y);
}

Date::Date(unsigned int y, unsigned int m, unsigned int d) {
	SetYear(y);
	SetMonth(m);
	SetDay(d);
}

Date::Date(const QDate& date) {
	SetYear(date.year());
	SetMonth(date.month());
	SetDay(date.day());
}

Date::Date(const nlohmann::json& json) {
	/* NOTE: this constructor is made for use with
	   AniList FuzzyDate-style JSON. In the future, some other
	   methods may be parsed and whatnot if necessary. */

	if (json.contains("/year"_json_pointer) && json.at("/year"_json_pointer).is_number())
		SetYear(json.at("/year"_json_pointer).get<unsigned int>());
	if (json.contains("/month"_json_pointer) && json.at("/month"_json_pointer).is_number())
		SetMonth(json.at("/month"_json_pointer).get<unsigned int>());
	if (json.contains("/day"_json_pointer) && json.at("/day"_json_pointer).is_number())
		SetDay(json.at("/day"_json_pointer).get<unsigned int>());
}

void Date::VoidYear() {
	year.reset();
}

void Date::VoidMonth() {
	month.reset();
}

void Date::VoidDay() {
	day.reset();
}

void Date::SetYear(unsigned int y) {
	year.emplace(y);
}

void Date::SetMonth(unsigned int m) {
	month.emplace(std::clamp(m, 1U, 12U));
}

void Date::SetDay(unsigned int d) {
	day.emplace(std::clamp(d, 1U, 31U));
}

std::optional<unsigned int> Date::GetYear() const {
	return year;
}

std::optional<unsigned int> Date::GetMonth() const {
	return month;
}

std::optional<unsigned int> Date::GetDay() const {
	return day;
}

bool Date::IsValid() const {
	return year.has_value() && month.has_value() && day.has_value();
}

QDate Date::GetAsQDate() const {
	/* QDate doesn't support "missing" values (for good reason),
	 * so we do our best and return what we can.
	*/

	return QDate(year.value_or(2000), month.value_or(1), day.value_or(1));
}

nlohmann::json Date::GetAsAniListJson() const {
	return {
		{"year", year},
		{"month", month},
		{"day", day}
	};
}
