#include "DeerRender/Log.h"
#include "DeerStudio/ResourceDataSource.h"

#include <fstream>
#include <sstream>
#include <vector>

namespace Deer {
	StorageData StorageBackend<ResourceDataSource>::loadData(const std::string& location) {
		Path path = Path("Resources") / location;
		std::ifstream file(path, std::ios::binary | std::ios::ate);
		if (!file.is_open()) {
			DEER_CORE_ERROR("Failed to open file '{}'", location.c_str());
			return StorageData();
		}

		auto size = file.tellg();
		if (size <= 0) {
			DEER_CORE_ERROR("File '{}' is empty or has invalid size", location.c_str());
			return StorageData();
		}

		StorageData data = StorageData(size);
		uint8_t* data_raw = data.getData();
		file.seekg(0, std::ios::beg);

		if (!file.read(reinterpret_cast<char*>(data_raw), size)) {
			DEER_CORE_ERROR("Failed to read full file '{}'", location.c_str());
			return StorageData();
		}

		return data;
	}

	void StorageBackend<ResourceDataSource>::saveData(const std::string& location, const StorageData& data) {
		Path path = Path("Resources") / location;
		std::ofstream file(path, std::ios::binary);
		if (!file.is_open()) {
			DEER_CORE_ERROR("Failed to open file '{}' for writing", location.c_str());
			return;
		}

		const uint8_t* data_raw = data.getData();
		size_t size = data.getSize();

		if (!file.write(reinterpret_cast<const char*>(data_raw), size)) {
			DEER_CORE_ERROR("Failed to write full data to file '{}'", location.c_str());
			return;
		}

		file.flush();
	}

	StorageMetadata StorageBackend<ResourceDataSource>::loadMetadata(const std::string& location) {
		Path path = Path("Resources") / (location + ".meta");
		StorageMetadata metadata;

		std::ifstream file(path);
		if (!file.is_open()) {
			DEER_CORE_TRACE("Failed to open metadata file '{}' for reading", path.string().c_str());
			return metadata;
		}

		std::string line;
		while (std::getline(file, line)) {
			// Skip empty lines or comments
			if (line.empty() || line[0] == '#')
				continue;

			auto pos = line.find(" : ");
			if (pos == std::string::npos)
				continue;

			std::string key = line.substr(0, pos);
			std::string value = line.substr(pos + 3); // skip " : "

			// Trim whitespace if needed
			auto trim = [](std::string& s) {
				s.erase(0, s.find_first_not_of(" \t\r\n"));
				s.erase(s.find_last_not_of(" \t\r\n") + 1);
			};
			trim(key);
			trim(value);

			metadata[key] = value;
		}

		return metadata;
	}

	void StorageBackend<ResourceDataSource>::saveMetadata(const StorageMetadata& metadata, const std::string& location) {
		Path path = Path("Resources") / (location + ".meta");

		std::stringstream metadataBuilder;
		metadataBuilder << "#Metadata file for resource " << location << "\n";

		for (const auto& part : metadata) {
			metadataBuilder << part.first << " : " << part.second << "\n";
		}

		std::ofstream file(path, std::ios::out | std::ios::trunc);
		if (!file.is_open()) {
			DEER_CORE_TRACE("Failed to open metadata file '{}' for writing", path.string().c_str());
			return;
		}

		file << metadataBuilder.str();
	}
} // namespace Deer