/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "MeshWriter.hpp"
#include "Scene/Geometry.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/UsdEncoder.hpp"
#include "Scene/ObjEncoder.hpp"
#include "IO/Archive/ArchiveWriter.hpp"
#include "IO/Archive/ZipWriter.hpp"

#include <fstream>
#include <fmt/core.h>

namespace OpenVulkano::Scene
{
	void MeshWriter::WriteAsOBJ(Geometry* geometry, const std::string& filePath)
	{
		std::ofstream file(filePath);

		if (!file.is_open())
			throw std::runtime_error("Failed to open file '" + filePath + "' for writing!");
		
		std::stringstream dummy;
		WriteObjContents(geometry, "", file, dummy);
		file.close();
	}

	void MeshWriter::WriteAsUSD(Geometry* geometry, const std::string& filePath)
	{
		std::ofstream file(filePath);
		if (!file.is_open())
			throw std::runtime_error("Failed to open file '" + filePath + "' for writing!");
		WriteUsdContents(file, geometry);
		file.close();
	}

	void MeshWriter::WriteObjAsZip(Geometry* geometry, const std::string& texturePath, const std::string& zipPath)
	{
		OpenVulkano::ArchiveWriter zipWriter(zipPath.c_str());

		std::stringstream objContents, mtlContents;
		WriteObjContents(geometry, texturePath, objContents, mtlContents);

		auto objDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("model.obj", objContents.str().size());
		zipWriter.AddFile(objDesc, objContents.str().data());

		auto mtlDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("material.mtl", mtlContents.str().size());
		zipWriter.AddFile(mtlDesc, mtlContents.str().data());

		if (!texturePath.empty() && std::filesystem::exists(texturePath))
		{
			auto textureFile = Utils::ReadFile(texturePath);
			auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
			zipWriter.AddFile(texDesc, textureFile.Data());
		}
	}

	void MeshWriter::WriteAsUSDZ(Geometry* geometry, const std::string& texturePath, const std::string& usdzPath)
	{
		OpenVulkano::ZipWriter zipWriter(usdzPath);
		
		std::stringstream usdFile;
		WriteUsdContents(usdFile, geometry);
		auto usdDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("geometry.usda", usdFile.str().size());
		zipWriter.AddFile(usdDesc, usdFile.str().data());

		if (!texturePath.empty() && std::filesystem::exists(texturePath))
		{
			auto textureFile = Utils::ReadFile(texturePath);
			auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
			zipWriter.AddFile(texDesc, textureFile.Data());
		}
	}
}