/*
 * Mirai. Copyright (C) 2024 Vyn
 * This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only)
 * The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt
 */

#pragma once

#include "DateTime.h"
#include <optional>
#include <string>
#include <vector>

namespace mirai
{

struct DayData {
	int id;
	Date date;
};

struct UpdatableDayData {
	std::optional<Date> date;
};

enum TaskState { TODO, DONE };

struct TaskData {
	int id;
	std::string title;
	TaskState state;
	std::optional<int> dayId;
	std::optional<int> eventId;
};

struct UpdatableTaskData {
	std::optional<std::string> title = std::nullopt;
	std::optional<TaskState> state = std::nullopt;
	std::optional<std::optional<int>> dayId = std::nullopt;
	std::optional<std::optional<int>> eventId = std::nullopt;
};

struct EventData {
	int id;
	int dayId;
	std::string title;
	Time startsAt;
	Time endsAt;
};

struct UpdatableEventData {
	std::optional<int> dayId;
	std::optional<std::string> title;
	std::optional<Time> startsAt;
	std::optional<Time> endsAt;
};

class DataProvider
{

  public:
	DataProvider() {};
	DataProvider(DataProvider &) = delete;
	DataProvider(DataProvider &&) = delete;

	virtual ~DataProvider() = default;
	virtual void save() = 0;
	virtual void load() = 0;

	virtual std::string name() const = 0;

	// Tasks
	virtual TaskData insertTask(const TaskData &task) = 0;
	virtual void removeTaskById(int taskId) = 0;
	virtual std::optional<TaskData> getTaskById(int taskId) = 0;
	virtual std::vector<TaskData> getTasksByEventId(int eventId) = 0;
	virtual std::vector<TaskData> getTasksByDayId(int dayId) = 0;
	virtual std::vector<TaskData> getTasksByDate(Date date) = 0;
	virtual std::vector<TaskData> getTasksWithoutDate() = 0;
	virtual std::vector<TaskData> getTasks() = 0;
	virtual void updateTask(int taskId, UpdatableTaskData updateData) = 0;

	// Events
	virtual EventData insertEvent(const EventData &task) = 0;
	virtual void removeEventById(int eventId) = 0;
	virtual std::optional<EventData> getEventById(int eventId) = 0;
	virtual std::vector<EventData> getEvents() = 0;
	virtual std::vector<EventData> getEventsByDate(Date date) = 0;
	virtual void updateEvent(int eventId, UpdatableEventData updateData) = 0;

	// Days
	virtual DayData insertDay(const DayData &day) = 0;
	virtual void removeDayById(int dayId) = 0;
	virtual std::vector<DayData> getDays() = 0;
	virtual std::optional<DayData> getDayByDate(const Date &date) = 0;
	virtual void updateDay(int dayId, UpdatableDayData updateData) = 0;

	const int id = DataProvider::generateNextId();

	void setDirty(bool dirty)
	{
		isDirty_ = dirty;
	};

	bool isDirty() const
	{
		return isDirty_;
	};

  private:
	bool isDirty_ = false;

	static int generateNextId()
	{
		static int nextId = 0;
		return nextId++;
	}
};

} // namespace mirai
