#include "gui/dialog/about.h"
#include "core/json.h"
#include "core/session.h"
#include "core/strings.h"
#include "gui/dialog/licenses.h"
#include "gui/widgets/text.h"

#include "utf8proc.h"
#include <fmt/format.h>
#include <toml11/toml.hpp>

#include <QCoreApplication>
#include <QFont>
#include <QHBoxLayout>
#include <QPushButton>
#include <QTextBrowser>
#include <QTextCharFormat>
#include <QTextCursor>

#include <curl/curl.h>
#ifdef WIN32
# include "sys/win32/dark_theme.h"
#endif

template<typename T, size_t N>
constexpr size_t array_size(T (&)[N])
{
	return N;
}

static constexpr semver::version fmt_version{FMT_VERSION / 10000, FMT_VERSION / 100 % 100, FMT_VERSION % 100};
static constexpr semver::version json_version{NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR,
                                              NLOHMANN_JSON_VERSION_PATCH};
static constexpr semver::version semver_version{SEMVER_VERSION_MAJOR, SEMVER_VERSION_MINOR, SEMVER_VERSION_PATCH};
static constexpr semver::version toml11_version{TOML11_VERSION_MAJOR, TOML11_VERSION_MINOR, TOML11_VERSION_PATCH};
static constexpr semver::version fugue_icons_version{3, 5, 6};

const char *get_curl_version()
{
	const curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
	return data->version;
}

static constexpr std::string_view about_template =
    "<body>"
    "<h2 style=\"font-weight: normal;\"><strong>Minori</strong> v{}</h2>"
    "<p><strong>Author:</strong><br>Paper &lt;paper@tflc.us&gt;</p>"
    "<p><strong>Third party components:</strong><br>"
    "<a href=\"https://curl.se/\">libcurl v{}</a>, "
    "<a href=\"https://p.yusukekamiyamane.com/\">Fugue Icons v{}</a>, "
    "<a href=\"https://github.com/erengy/anitomy\">Anitomy</a>, "
    "<a href=\"https://github.com/nlohmann/json\">JSON for Modern C++ v{}</a>, "
    "<a href=\"https://github.com/Neargye/semver\">semver v{}</a>, "
    "<a href=\"http://juliastrings.github.io/utf8proc/\">utf8proc v{}</a>, "
    "<a href=\"https://github.com/fmtlib/fmt\">fmt v{}</a>, "
    "<a href=\"https://github.com/ToruNiina/toml11\">toml11 v{}</a>, "
    "and parts of <a href=\"https://github.com/erengy/anisthesia\">Anisthesia</a>"
    "</p>"
    "<span><strong>Special thanks:</strong></span>"
    "<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 15px; margin-right: 0px; -qt-list-indent:0;\">"
    "<li><strong>Eren Okka</strong> for creating <a href=\"https://taiga.moe/\">Taiga</a></li>"
    "<li><strong>Alex Huszagh</strong> and <strong>Colin Duquesnoy</strong> for creating BreezeStyleSheets, on which "
    "the dark theme in this program is based off of</li>"
    "<li><strong>Andy Brice</strong> for providing some sample code for detecting dark mode on Windows and macOS</li>"
    "<li><strong>Manuel Wudka-Robles</strong> for providing information on getting open file descriptors on macOS</li>"
    "</ul>"
    "</body>";

AboutWindow::AboutWindow(QWidget *parent) : Dialog(parent)
{
	setMinimumSize(641, 325);
	setWindowTitle(tr("About Minori"));
	setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
	setAutoFillBackground(true);

	QVBoxLayout *layout = new QVBoxLayout(this);

	std::string html =
	    fmt::format(about_template, session.version.to_string(), get_curl_version(), fugue_icons_version.to_string(),
	                json_version.to_string(), semver_version.to_string(), utf8proc_version(), fmt_version.to_string(),
	                toml11_version.to_string());

	setBackgroundRole(QPalette::Base);

	{
		QTextBrowser *paragraph = new QTextBrowser(this);
		paragraph->setOpenExternalLinks(true);
		paragraph->setFrameShape(QFrame::NoFrame);
		paragraph->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
		paragraph->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
		paragraph->setHtml(Strings::ToQString(html));

		layout->addWidget(paragraph);
	}

	{
		QPushButton *license = new QPushButton("&Licenses", this);
		layout->addWidget(license, Qt::AlignRight);
		connect(license, &QPushButton::clicked, this, [] {
			LicensesWindow dialog;
			dialog.exec();
		});
	}
}
