/* SPDX-FileCopyrightText: 2026 Project Tick
 * SPDX-FileContributor: Project Tick
 * SPDX-License-Identifier: GPL-3.0-or-later WITH LicenseRef-MeshMC-MMCO-Module-Exception-1.0
 *
 *   MeshMC - A Custom Launcher for Minecraft
 *   Copyright (C) 2026 Project Tick
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version, with the additional permission
 *   described in the MeshMC MMCO Module Exception 1.0.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 *   You should have received a copy of the MeshMC MMCO Module Exception 1.0
 *   along with this program.  If not, see <https://projecttick.org/licenses/>.
 */

#include "FlamePackIndex.h"

#include "Json.h"

void Flame::loadIndexedPack(Flame::IndexedPack& pack, QJsonObject& obj)
{
	pack.addonId = Json::requireInteger(obj, "id");
	pack.name = Json::requireString(obj, "name");
	pack.description = Json::ensureString(obj, "summary", "");

	// API v1: links.websiteUrl, API v2: websiteUrl at root
	if (obj.contains("links") && obj.value("links").isObject()) {
		pack.websiteUrl =
			Json::ensureString(obj.value("links").toObject(), "websiteUrl", "");
	} else {
		pack.websiteUrl = Json::ensureString(obj, "websiteUrl", "");
	}

	// API v1: logo is a single object, API v2: attachments is an array
	bool thumbnailFound = false;
	if (obj.contains("logo") && obj.value("logo").isObject()) {
		auto logoObj = obj.value("logo").toObject();
		pack.logoName = Json::ensureString(logoObj, "title", pack.name);
		pack.logoUrl = Json::ensureString(logoObj, "thumbnailUrl", "");
		thumbnailFound = !pack.logoUrl.isEmpty();
	}
	if (!thumbnailFound && obj.contains("attachments")) {
		auto attachments = Json::requireArray(obj, "attachments");
		for (auto attachmentRaw : attachments) {
			auto attachmentObj = Json::requireObject(attachmentRaw);
			bool isDefault = attachmentObj.value("isDefault").toBool(false);
			if (isDefault) {
				thumbnailFound = true;
				pack.logoName = Json::requireString(attachmentObj, "title");
				pack.logoUrl =
					Json::requireString(attachmentObj, "thumbnailUrl");
				break;
			}
		}
	}
	if (!thumbnailFound) {
		pack.logoName = pack.name;
		pack.logoUrl = "";
	}

	auto authors = Json::requireArray(obj, "authors");
	for (auto authorIter : authors) {
		auto author = Json::requireObject(authorIter);
		Flame::ModpackAuthor packAuthor;
		packAuthor.name = Json::requireString(author, "name");
		packAuthor.url = Json::ensureString(author, "url", "");
		pack.authors.append(packAuthor);
	}

	// API v1: mainFileId, API v2: defaultFileId
	int defaultFileId = 0;
	if (obj.contains("mainFileId")) {
		defaultFileId = Json::requireInteger(obj, "mainFileId");
	} else {
		defaultFileId = Json::requireInteger(obj, "defaultFileId");
	}

	bool found = false;
	// check if there are some files before adding the pack
	auto files = Json::ensureArray(obj, "latestFiles");
	for (auto fileIter : files) {
		auto file = Json::requireObject(fileIter);
		int id = Json::requireInteger(file, "id");

		// NOTE: for now, ignore everything that's not the default...
		if (id != defaultFileId) {
			continue;
		}

		// API v1: gameVersions, API v2: gameVersion
		QJsonArray versionArray;
		if (file.contains("gameVersions")) {
			versionArray = Json::requireArray(file, "gameVersions");
		} else {
			versionArray = Json::requireArray(file, "gameVersion");
		}
		if (versionArray.size() < 1) {
			continue;
		}

		found = true;
		break;
	}
	if (!found) {
		throw JSONValidationError(
			QString("Pack with no good file, skipping: %1").arg(pack.name));
	}
}

void Flame::loadIndexedPackVersions(Flame::IndexedPack& pack, QJsonArray& arr)
{
	QVector<Flame::IndexedVersion> unsortedVersions;
	for (auto versionIter : arr) {
		auto version = Json::requireObject(versionIter);
		Flame::IndexedVersion file;

		file.addonId = pack.addonId;
		file.fileId = Json::requireInteger(version, "id");
		QJsonArray versionArray;
		if (version.contains("gameVersions")) {
			versionArray = Json::requireArray(version, "gameVersions");
		} else {
			versionArray = Json::requireArray(version, "gameVersion");
		}
		if (versionArray.size() < 1) {
			continue;
		}

		// pick the latest version supported
		file.mcVersion = versionArray[0].toString();
		file.version = Json::requireString(version, "displayName");
		file.downloadUrl = Json::ensureString(version, "downloadUrl", "");
		file.fileName = Json::ensureString(version, "fileName", "");
		unsortedVersions.append(file);
	}

	auto orderSortPredicate = [](const IndexedVersion& a,
								 const IndexedVersion& b) -> bool {
		return a.fileId > b.fileId;
	};
	std::sort(unsortedVersions.begin(), unsortedVersions.end(),
			  orderSortPredicate);
	pack.versions = unsortedVersions;
	pack.versionsLoaded = true;
}
