// Reproduces the exact pack-registration flow the real client performs in
// PackInitialize() (UserInterface.cpp): parses the pack folder's "Index"
// manifest and registers every listed pack (plus root) into one real
// CEterPackManager, exactly like the running game does. This is the only
// reliable way to verify a pack, because single-pack tools (PackVerify) can't
// catch bugs in how a file's stored path lines up with what the manager's
// merged, folder-prefixed lookup actually queries for.
//
// Usage:
//   PackManagerSim.exe <packFolder> <fileNameToLookup>
//     Looks up one file through the full manager, e.g.:
//     PackManagerSim.exe "Y:\Metin2Dev\Exec_Client\pack" "UIScript/PopupDialog.py"
//
//   PackManagerSim.exe <packFolder> --verify-all <dbname>
//     Registers all packs, then checks that every entry of <dbname> (read
//     directly from its own .eix) resolves through the full manager, e.g.:
//     PackManagerSim.exe "Y:\Metin2Dev\Exec_Client\pack" --verify-all uiscript

#include <windows.h>
#include <cstdio>
#include <string>
#include <vector>
#include <fstream>

#include "../EterPack/EterPackManager.h"
#include "../EterBase/lzo.h"

int main(int argc, char** argv)
{
	CLZO lzoInstance;

	if (argc < 3)
	{
		fprintf(stderr, "Usage: %s <packFolder> <fileNameToLookup>\n", argv[0]);
		fprintf(stderr, "   or: %s <packFolder> --verify-all <dbname>\n", argv[0]);
		return 1;
	}

	std::string packFolder = argv[1];
	std::string lookupName = argv[2];
	std::string verifyDbname = (argc >= 4) ? argv[3] : "";

	std::string stFolder = packFolder + "/";
	std::string indexPath = stFolder + "Index";

	std::ifstream indexFile(indexPath);
	if (!indexFile)
	{
		fprintf(stderr, "Cannot open Index file: %s\n", indexPath.c_str());
		return 2;
	}

	std::vector<std::string> lines;
	std::string line;
	while (std::getline(indexFile, line))
	{
		while (!line.empty() && (line.back() == '\r' || line.back() == '\n'))
			line.pop_back();
		lines.push_back(line);
	}

	if (lines.empty() || (lines[0] != "FILE" && lines[0] != "PACK"))
	{
		fprintf(stderr, "Invalid Index syntax\n");
		return 3;
	}

	CEterPackManager manager;
	manager.SetSearchMode(true); // _DISTRIBUTE build: pack-first

	int registered = 0, failed = 0;

	for (size_t i = 1; i + 1 < lines.size(); i += 2)
	{
		const std::string& rstFolder = lines[i];
		const std::string& rstName = lines[i + 1];

		std::string packName = stFolder + rstName;
		std::string texCacheName = packName + "_texcache";

		if (manager.RegisterPack(packName.c_str(), rstFolder.c_str()))
			++registered;
		else
			++failed;

		manager.RegisterPack(texCacheName.c_str(), rstFolder.c_str());
	}

	manager.RegisterRootPack((stFolder + "root").c_str());

	printf("Registered %d packs (%d failed to open) from Index\n", registered, failed);

	if (lookupName == "--verify-all")
	{
		if (verifyDbname.empty())
		{
			fprintf(stderr, "--verify-all requires a <dbname> argument\n");
			return 12;
		}

		std::string dbname = stFolder + verifyDbname;
		CEterFileDict rawDict;
		CEterPack rawPack;
		if (!rawPack.Create(rawDict, dbname.c_str(), "", true))
		{
			fprintf(stderr, "Cannot open raw pack '%s'\n", dbname.c_str());
			return 20;
		}

		std::vector<std::string> names;
		rawPack.GetNames(&names);

		int ok = 0, bad = 0;
		for (auto& n : names)
		{
			CMappedFile mf;
			LPCVOID d = NULL;
			if (manager.Get(mf, n.c_str(), &d))
				++ok;
			else
			{
				++bad;
				printf("  MISSING VIA MANAGER: %s\n", n.c_str());
			}
		}
		printf("verify-all '%s': %d/%zu OK via manager, %d missing\n", verifyDbname.c_str(), ok, names.size(), bad);
		return bad > 0 ? 11 : 0;
	}

	CMappedFile mappedFile;
	LPCVOID data = NULL;

	bool ok = manager.Get(mappedFile, lookupName.c_str(), &data);

	printf("Get(\"%s\") => %s", lookupName.c_str(), ok ? "FOUND" : "NOT FOUND");
	if (ok)
		printf(" (%lu bytes)", mappedFile.Size());
	printf("\n");

	return ok ? 0 : 10;
}
