/* 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/>.
 *
 *  This file incorporates work covered by the following copyright and
 *  permission notice:
 *
 * Copyright 2013-2021 MultiMC Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "LegacyModList.h"
#include <FileSystem.h>
#include <QString>
#include <QDebug>

LegacyModList::LegacyModList(const QString& dir, const QString& list_file)
	: m_dir(dir), m_list_file(list_file)
{
	FS::ensureFolderPathExists(m_dir.absolutePath());
	m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files |
					QDir::Dirs);
	m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
}

struct OrderItem {
	QString id;
	bool enabled = false;
};
typedef QList<OrderItem> OrderList;

static void internalSort(QList<LegacyModList::Mod>& what)
{
	auto predicate = [](const LegacyModList::Mod& left,
						const LegacyModList::Mod& right) {
		return left.fileName().localeAwareCompare(right.fileName()) < 0;
	};
	std::sort(what.begin(), what.end(), predicate);
}

static OrderList readListFile(const QString& m_list_file)
{
	OrderList itemList;
	if (m_list_file.isNull() || m_list_file.isEmpty())
		return itemList;

	QFile textFile(m_list_file);
	if (!textFile.open(QIODevice::ReadOnly | QIODevice::Text))
		return OrderList();

	QTextStream textStream;
	textStream.setAutoDetectUnicode(true);
	textStream.setDevice(&textFile);
	while (true) {
		QString line = textStream.readLine();
		if (line.isNull() || line.isEmpty())
			break;
		else {
			OrderItem it;
			it.enabled = !line.endsWith(".disabled");
			if (!it.enabled) {
				line.chop(9);
			}
			it.id = line;
			itemList.append(it);
		}
	}
	textFile.close();
	return itemList;
}

bool LegacyModList::update()
{
	if (!m_dir.exists() || !m_dir.isReadable())
		return false;

	QList<Mod> orderedMods;
	QList<Mod> newMods;
	m_dir.refresh();
	auto folderContents = m_dir.entryInfoList();

	// first, process the ordered items (if any)
	OrderList listOrder = readListFile(m_list_file);
	for (auto item : listOrder) {
		QFileInfo infoEnabled(m_dir.filePath(item.id));
		QFileInfo infoDisabled(m_dir.filePath(item.id + ".disabled"));
		int idxEnabled = folderContents.indexOf(infoEnabled);
		int idxDisabled = folderContents.indexOf(infoDisabled);
		bool isEnabled;
		// if both enabled and disabled versions are present, it's a special
		// case...
		if (idxEnabled >= 0 && idxDisabled >= 0) {
			// we only process the one we actually have in the order file.
			// and exactly as we have it.
			// THIS IS A CORNER CASE
			isEnabled = item.enabled;
		} else {
			// only one is present.
			// we pick the one that we found.
			// we assume the mod was enabled/disabled by external means
			isEnabled = idxEnabled >= 0;
		}
		int idx = isEnabled ? idxEnabled : idxDisabled;
		QFileInfo& info = isEnabled ? infoEnabled : infoDisabled;
		// if the file from the index file exists
		if (idx != -1) {
			// remove from the actual folder contents list
			folderContents.takeAt(idx);
			// append the new mod
			orderedMods.append(info);
		}
	}
	// if there are any untracked files... append them sorted at the end
	if (folderContents.size()) {
		for (auto entry : folderContents) {
			newMods.append(entry);
		}
		internalSort(newMods);
		orderedMods.append(newMods);
	}
	mods.swap(orderedMods);
	return true;
}
