#ifndef MINORI_LIBRARY_LIBRARY_H_
#define MINORI_LIBRARY_LIBRARY_H_

#include "core/filesystem.h"
#include "library/library.h"

#include <filesystem>
#include <optional>
#include <unordered_map>
#include <thread>
#include <mutex>

namespace Library {

class Database final {
public:
	Database();
	~Database();

	/* Update watchers from current library paths */
	void UpdateWatchers();

	bool GetPathAnimeAndEpisode(const std::string &basename, int *aid, int *ep);

	void EventHandler(const std::filesystem::path &path, Filesystem::IWatcher::Event event);
	static void StaticEventHandler(void *opaque, const std::filesystem::path &path, Filesystem::IWatcher::Event event);

	std::optional<std::filesystem::path> GetAnimeFolder(int id);
	void Refresh();
	void Refresh(int id);

	std::optional<std::filesystem::path> GetAnimeEpisodePath(int anime, int episode);

private:
	void Refresh(std::optional<int> find_id);
	/* refresh_thread entry point */
	void RefreshThread();

	Filesystem::PathMap<std::unique_ptr<Filesystem::IWatcher>> watchers_;

	/* ID we're looking for (This is terrible, but other ways are also terrible in their own unique ways) */
	std::optional<int> find_id_;

	/* Anime episodes. Indexed as `folders[id][episode]' */
	std::unordered_map<int, std::unordered_map<int, std::filesystem::path>> items;
	std::recursive_mutex items_mutex_;

	/* Thread that runs the refreshing.
	 * When Refresh() is called, if this is a valid thread, then it will be
	 * join()'d. This stinks, and a better method would be to have the
	 * thread running in the background waiting on a queue. Oh well. */
	std::thread refresh_thread_;
};

extern Database db;

} // namespace Library

#endif // MINORI_LIBRARY_LIBRARY_H_
