#include "SaveLoadSystem.hpp"
#include <OgreLogManager.h>
#include <ctime>
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <sstream>

/* ===================================================================== */
/*  OS-dependent save directory                                          */
/* ===================================================================== */

std::string SaveLoadSystem::getSaveDirectory()
{
	std::string dir;

#ifdef _WIN32
	const char *appdata = getenv("APPDATA");
	if (appdata)
		dir = std::string(appdata) + "/World2/saves/";
	else
		dir = "./saves/";
#elif defined(__APPLE__)
	const char *home = getenv("HOME");
	if (home)
		dir = std::string(home) +
		      "/Library/Application Support/World2/saves/";
	else
		dir = "./saves/";
#else /* Linux */
	const char *xdgDataHome = getenv("XDG_DATA_HOME");
	if (xdgDataHome)
		dir = std::string(xdgDataHome) + "/World2/saves/";
	else {
		const char *home = getenv("HOME");
		if (home)
			dir = std::string(home) + "/.local/share/World2/saves/";
		else
			dir = "./saves/";
	}
#endif

	std::filesystem::create_directories(dir);
	return dir;
}

/* ===================================================================== */
/*  Save slot management                                                 */
/* ===================================================================== */

std::vector<SaveLoadSystem::SaveInfo> SaveLoadSystem::listSaves()
{
	std::vector<SaveInfo> result;
	std::string dir = getSaveDirectory();

	if (!std::filesystem::exists(dir))
		return result;

	for (const auto &entry :
	     std::filesystem::directory_iterator(dir)) {
		if (!entry.is_regular_file())
			continue;
		std::string ext = entry.path().extension().string();
		if (ext != ".json")
			continue;

		nlohmann::json data;
		std::ifstream file(entry.path());
		if (!file.is_open())
			continue;
		try {
			file >> data;
		} catch (...) {
			continue;
		}
		file.close();

		SaveInfo info;
		info.path = entry.path().string();
		info.filename = entry.path().filename().string();
		if (data.contains("saveGame") && data["saveGame"].is_object()) {
			auto &sg = data["saveGame"];
			info.slotName = sg.value("slotName", info.filename);
			info.timestamp = sg.value("timestamp", "");
			info.playTime = sg.value("playTime", 0.0f);
			info.baseScene = sg.value("baseScene", "");
		}
		result.push_back(info);
	}

	/* Sort by filename (save index) so UI order is stable */
	std::sort(result.begin(), result.end(),
		  [](const SaveInfo &a, const SaveInfo &b) {
			  return a.filename < b.filename;
		  });
	return result;
}

std::string SaveLoadSystem::generateSaveFilename()
{
	std::string dir = getSaveDirectory();
	int index = 1;
	while (true) {
		std::stringstream ss;
		ss << dir << "save_" << std::setfill('0') << std::setw(3)
		   << index << ".json";
		std::string path = ss.str();
		if (!std::filesystem::exists(path))
			return path;
		++index;
	}
}

bool SaveLoadSystem::deleteSave(const std::string &path)
{
	try {
		return std::filesystem::remove(path);
	} catch (...) {
		return false;
	}
}

/* ===================================================================== */
/*  File I/O                                                             */
/* ===================================================================== */

bool SaveLoadSystem::writeSaveFile(const std::string &path,
				   const nlohmann::json &data)
{
	try {
		std::ofstream file(path);
		if (!file.is_open()) {
			Ogre::LogManager::getSingleton().logMessage(
				"SaveLoadSystem: failed to open file for writing: " +
				path);
			return false;
		}
		file << data.dump(4);
		file.close();
		return true;
	} catch (const std::exception &e) {
		Ogre::LogManager::getSingleton().logMessage(
			"SaveLoadSystem: write error: " +
			Ogre::String(e.what()));
		return false;
	}
}

bool SaveLoadSystem::readSaveFile(const std::string &path,
				  nlohmann::json &outData)
{
	try {
		std::ifstream file(path);
		if (!file.is_open()) {
			Ogre::LogManager::getSingleton().logMessage(
				"SaveLoadSystem: failed to open file for reading: " +
				path);
			return false;
		}
		file >> outData;
		file.close();
		return true;
	} catch (const std::exception &e) {
		Ogre::LogManager::getSingleton().logMessage(
			"SaveLoadSystem: read error: " +
			Ogre::String(e.what()));
		return false;
	}
}

/* ===================================================================== */
/*  Timestamp helper                                                     */
/* ===================================================================== */

std::string SaveLoadSystem::getCurrentTimestamp()
{
	auto now = std::time(nullptr);
	auto tm = *std::localtime(&now);
	std::ostringstream oss;
	oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
	return oss.str();
}
