#include "SH_plugin_manifest.h"
#include "pip_version.h"
#include "qad_version.h"
#include "SH_version_gen.h"
#include "SH_plugin_base.h"
#include <QFileInfo>
#include <QFile>
#include <QDir>
#include <QLibrary>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>


bool SHPluginManifest::read(const QString & path) {
	manifestpath = path;
	QFile f(path);
	if (!f.open(QIODevice::ReadOnly)) {
		qDebug() << "[SHPluginManifest::read] Can`t open" << path;
		return false;
	}
	if (!read(f.readAll())) return false;
	//qDebug() << libpath << name << dependencies << timestamp;
	return checkFile();
}


#define READ_STRING(f) f = manifest.value(#f).toString().trimmed()

bool SHPluginManifest::read(const QByteArray & content) {
	manifestcontent = content;
	QJsonDocument doc = QJsonDocument::fromJson(content);
	QJsonObject manifest = doc.object();
	READ_STRING(file);
	READ_STRING(name);
	READ_STRING(author);
	READ_STRING(description);
	READ_STRING(version);
	READ_STRING(version_PIP);
	READ_STRING(version_QAD);
	READ_STRING(version_SHS);
	READ_STRING(build);
	READ_STRING(system);
	READ_STRING(arch);
	auto darr = manifest.value("dependencies").toArray();
	for (auto i: darr)
		dependencies << i.toString();
	timestamp = QDateTime::fromString(manifest.value("timestamp").toString(), "yyyy-M-d h:m:s");

	//qDebug() << libpath << name << dependencies << timestamp;
	return checkSystem();
}

#undef READ_STRING


bool SHPluginManifest::checkFile() const {
	libpath = QFileInfo(manifestpath).absoluteDir().absoluteFilePath(file);
	if (!QFile::exists(libpath)) {
		qDebug() << "[SHPluginManifest::checkFile] File doesn`t exists" << libpath;
		return false;
	}
	if (!QLibrary::isLibrary(libpath)) {
		qDebug() << "[SHPluginManifest::checkFile] File is not library" << libpath;
		return false;
	}
	return true;
}


bool SHPluginManifest::checkSystem() const {
	if (system != SHS_CMAKE_OS) {
		if (!manifestpath.isEmpty()) qDebug() << "[SHPluginManifest::checkVersions] Mismatch system," << system << "!=" << QString(SHS_CMAKE_OS) << "(" << manifestpath << ")";
		return false;
	}
	if (arch != SHS_CMAKE_ARCH) {
		if (!manifestpath.isEmpty()) qDebug() << "[SHPluginManifest::checkVersions] Mismatch arch," << arch << "!=" << QString(SHS_CMAKE_ARCH) << "(" << manifestpath << ")";
		return false;
	}
	return true;
}


bool SHPluginManifest::checkVersions() const {
	if (!checkVersion(version_PIP, PIP_VERSION_NAME, "PIP")) return false;
	if (!checkVersion(version_QAD, QAD_VERSION_NAME, "QAD")) return false;
	if (!checkVersion(version_SHS, SHS_VERSION_NAME, "SHS")) return false;
	return true;
}


void SHPluginManifest::fillBuiltin(SHPluginBase * plugin) {
	builtin = true;
	system = SHS_CMAKE_OS;
	arch = SHS_CMAKE_ARCH;
	timestamp = QDateTime::fromString(SHS_BUILD_DATE, "d.M.yyyy h:m");
	version_PIP = PIP_VERSION_NAME;
	version_QAD = QAD_VERSION_NAME;
	version_SHS = SHS_VERSION_NAME;
	version = plugin->version();
	name = plugin->name();
	description = plugin->description();
}


QString SHPluginManifest::fullVersion() const {
	return version + " (" + build + ")";
}


QString SHPluginManifest::libraryDownloadPath() const {
	return QFileInfo(manifestpath).dir().filePath(file);
}


PIString SHPluginManifest::comparableVersion() const {
	return versionNormalize(Q2PIString(version)) + "." + Q2PIString(build);
}


bool SHPluginManifest::checkVersion(const QString & v0, const QString & v1, const char * name) const {
	auto v0mm = versionComponents(v0), v1mm = versionComponents(v1);
	if (v0mm == v1mm) return true;
	if (!manifestpath.isEmpty()) qDebug() << "[SHPluginManifest::checkVersions] Mismatch" << name << "version," << v0 << "!=" << v1 << "(" << manifestpath << ")";
	return false;
}


QString SHPluginManifest::versionComponents(const QString & v, int count) const {
	int ind = -1;
	for (int i = 0; i < count; ++i) {
		ind = v.indexOf('.', ind + 1);
		if (ind < 0) return QString();
	}
	return v.left(ind);
}
