// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2011 Konrad Twardowski

#include "udialog.h"

#include "commandline.h"
#include "config.h"
#include "ulabel.h"
#include "utils.h"
#include "version.h"

#include <QMessageBox>
#include <QPushButton>
#include <QScreen>
#include <QStyle>
#include <QTabWidget>
#include <QTimeZone>

// public:

UDialog::UDialog(QWidget *parent, const QString &windowTitle, const bool simple) :
	QDialog(parent) {

	setWindowFlag(Qt::WindowContextHelpButtonHint, false); // hide unused titlebar "?" button
	setWindowTitle(windowTitle);

	if (simple) {
		m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Close);
		m_acceptButton = m_dialogButtonBox->button(QDialogButtonBox::Close);
	}
	else {
		m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
		m_acceptButton = m_dialogButtonBox->button(QDialogButtonBox::Ok);
	}

	connect(m_dialogButtonBox, SIGNAL(accepted()), SLOT(accept()));
	connect(m_dialogButtonBox, SIGNAL(rejected()), SLOT(reject()));

	auto *mainWidget = new QWidget(this);
	m_mainLayout = Utils::newVBoxLayout(mainWidget, { }, 10_px);

	m_rootLayout = Utils::newVBoxLayout(this, { mainWidget, m_dialogButtonBox }, 10_px, 10_px);
}

void UDialog::moveToCenterOfScreen() {
	QSize dialogSize = sizeHint();

// TODO: #qt5.14 QScreen *screen = dialog->screen();
	QScreen *screen = QApplication::primaryScreen();

	QRect desktopRect = screen->availableGeometry();
	move(
		(desktopRect.width() / 2) - (dialogSize.width() / 2) + desktopRect.x(),
		(desktopRect.height() / 2) - (dialogSize.height() / 2) + desktopRect.y()
	);
}

void UDialog::setWindowSize(const WindowSize windowSize) {
	double f = 0;
	switch (windowSize) {
		case WindowSize::FIXED:
			layout()->setSizeConstraint(QLayout::SetFixedSize);
			//resize(sizeHint());

			return;

		case WindowSize::LARGE:
			f = 0.7;
			break;
	}

	auto *screen = QApplication::primaryScreen();
	auto size = screen->availableSize();

	int w = qBound(800_px, (int)(size.width() * f), 1200_px);
	int h = qBound(600_px, (int)(size.height() * f), 700_px);

	resize(w, h);
}

// messages

void UDialog::error(QWidget *parent, const QString &text, const Qt::TextFormat format) {
	UMessageBuilder message(UMessageBuilder::Type::Error);
	message.text(text, format);
	message.exec(parent);
}

void UDialog::info(QWidget *parent, const QString &text, const Qt::TextFormat format) {
	UMessageBuilder message(UMessageBuilder::Type::Info);
	message.text(text, format);
	message.exec(parent);
}

void UDialog::warning(QWidget *parent, const QString &text, const Qt::TextFormat format) {
	UMessageBuilder message(UMessageBuilder::Type::Warning);
	message.text(text, format);
	message.exec(parent);
}

// misc

#ifdef KS_PURE_QT
void UDialog::about(QWidget *parent) {
	auto *topLabel = new ULabel();
	topLabel->setMarginAndSpacing(0_px, 20_px);
	topLabel->iconLabel()->setAlignment(Qt::AlignCenter);

	QIcon logo = QApplication::windowIcon();
	topLabel->setIcon(logo, 64_px);

	QString titleText = "KShutdown™ " + QApplication::applicationVersion();
	QString buildText = KS_RELEASE_DATE;
	if (Config::isPortable())
		buildText += " | Portable";
	topLabel->setText(Utils::makeHTML(
		"<h1 style=\"margin: 0px; white-space: nowrap\">" + titleText + "</h1>" +
		"<b style=\"white-space: nowrap\">" + buildText + "</b>"
	));
	topLabel->textLabel()->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
	topLabel->textLabel()->setTextInteractionFlags(Qt::TextBrowserInteraction);

	QUrl homePage = QUrl(KS_HOME_PAGE);

	auto *aboutLabel = new QLabel();
	aboutLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
	aboutLabel->setOpenExternalLinks(true);
	aboutLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
	aboutLabel->setText(Utils::makeHTML(
		CLI::getArgs()->applicationDescription() + "<br />" +
		Utils::makeLink(aboutLabel, homePage.toString(), homePage.host())
	));

	auto *aboutTab = new QWidget();
	auto *aboutLayout = Utils::newVBoxLayout(
		aboutTab,
		{ },
		20_px, 20_px
	);
	aboutLayout->addWidget(topLabel);
	aboutLayout->addWidget(aboutLabel);
	aboutLayout->addStretch();

	if (Utils::isAntique())
		aboutLayout->addWidget(InfoWidget::info(Utils::getAntiqueMessage()));

	auto *licenseLabel = new QLabel();

QString licenseText =
	KS_COPYRIGHT + "<br>" +
	"<br>";

licenseText += QString(
R"(This program is <b>free software</b>; 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 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but <b>WITHOUT ANY WARRANTY</b>; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%1 for more details. (%2))")
	.arg(Utils::makeLink(licenseLabel, "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html", "GNU General Public License"))
	.arg(Utils::makeLink(licenseLabel, "https://www.tldrlegal.com/license/gnu-general-public-license-v2", "tl;dr"));

	licenseText = licenseText.replace("\n", "<br />");

	licenseLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
	licenseLabel->setOpenExternalLinks(true);
	licenseLabel->setText(Utils::makeHTML(licenseText));
	licenseLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);

	auto *licenseTab = new QWidget();
	Utils::newVBoxLayout(
		licenseTab,
		{ licenseLabel },
		20_px, 20_px
	);
// TODO: https://sourceforge.net/p/kshutdown/wiki/Credits/

	auto dialog = std::make_unique<UDialog>(parent, i18n("About"), true);

	auto *closeButton = dialog->buttonBox()->button(QDialogButtonBox::Close);
	closeButton->setDefault(true);

	auto *aboutQtButton = dialog->buttonBox()->addButton(i18n("About Qt"), QDialogButtonBox::ActionRole);
	connect(aboutQtButton, SIGNAL(clicked()), qApp, SLOT(aboutQt()));

	#ifdef Q_OS_WIN32
	Utils::setMargin(dialog->rootLayout(), 5_px);
	dialog->rootLayout()->setSpacing(5_px);
	#endif // Q_OS_WIN32

	auto *tabs = new QTabWidget();
	tabs->addTab(aboutTab, i18n("About"));
	tabs->addTab(licenseTab, i18n("License"));
	dialog->mainLayout()->addWidget(tabs);
	tabs->setFocus();

	dialog->setWindowSize(WindowSize::FIXED);
	dialog->exec();
}
#endif // KS_PURE_QT

void UDialog::largeWidget(QWidget *parent, QWidget *widget, const QString &windowTitle, const QList<QPushButton *> &actionButtonList) {
	auto dialog = std::make_unique<UDialog>(parent, windowTitle, true);
	auto *buttonBox = dialog->buttonBox();

	auto *closeButton = buttonBox->button(QDialogButtonBox::Close);
	closeButton->setDefault(true);

	auto *buttonBoxLayout = dynamic_cast<QHBoxLayout *>(buttonBox->layout());

	if (buttonBoxLayout != nullptr)
		buttonBoxLayout->setSpacing(20_px);

	for (auto *actionButton : actionButtonList) {
		buttonBox->addButton(actionButton, QDialogButtonBox::ActionRole);
	}

	dialog->mainLayout()->addWidget(widget);
	widget->setFocus();

	dialog->setSizeGripEnabled(true);
	dialog->setWindowSize(UDialog::WindowSize::LARGE);
	dialog->exec();
}

void UDialog::plainText(QWidget *parent, const QString &text, const QString &windowTitle) {
	auto *textEdit = Utils::newTextEdit(text);
	textEdit->setReadOnly(true);

	largeWidget(parent, textEdit, windowTitle, { });
}

void UDialog::systemInfo(QWidget *parent) {
	auto *htmlWidget = Utils::newHTMLView();

	auto *primaryScreen = QApplication::primaryScreen();

	QString configValue = Config::getPath();
	if (configValue.startsWith("\\HKEY_CURRENT_USER\\")) {
		configValue = "Registry: " + configValue;
	}
	else {
		UPath path = configValue.toStdString();
		QString dir = QString::fromStdString(path.parent_path().string());
		QString name = QString::fromStdString(path.filename().string());

		QUrl url = QUrl::fromLocalFile(dir);
		configValue = Utils::makeLink(htmlWidget, url.toString(), dir) + "/" + name.toHtmlEscaped();
	}

	QString dataValue = Config::getDataDirectory();
	QUrl url = QUrl::fromLocalFile(dataValue);
	dataValue = Utils::makeLink(htmlWidget, url.toString(), dataValue);

	QList<QStringList> rows {
		{ Utils::getApplicationVersionInfo() },
		{ Utils::getQtVersionInfo() },

		{ },

		{ "Build Type", Utils::getBuildTypeInfo() },

		{ },

		{ "Desktop", Utils::getDesktopInfo() },
		{
			"Style",
			#if QT_VERSION < QT_VERSION_CHECK(6, 1, 0)
			QApplication::style()->objectName()
			#else
			QApplication::style()->name()
			#endif // QT_VERSION
		},
		{ "Icon Theme", QIcon::themeName() },
		{ "Platform", QApplication::platformName() },
		{ "Screen", QString("%1 x %2 | Scale=%3x")
			.arg(primaryScreen->size().width())
			.arg(primaryScreen->size().height())
			.arg(primaryScreen->devicePixelRatio()) },

		{ },

		{ "System", Utils::getSystemInfo() },
		{ "Locale", QString("%1 | %2 | %3")
			.arg(QLocale::system().name())
			.arg(QLocale::system().bcp47Name())
			.arg(QString(QTimeZone::systemTimeZoneId())) },

		{ },

		{ "Config", configValue },
		{ "Data", dataValue },
	};

	#ifdef Q_OS_LINUX
	QFileInfo appImage = Utils::getAppImageInfo();

	if (appImage.isFile())
		rows += QStringList({ "AppImage", appImage.filePath() });
	#endif // Q_OS_LINUX

	QString html = "";

	QString fontFamily = Utils::getMonospaceFontName();
	html += "<table cellspacing=\"0\" cellpadding=\"1\" style=\"font-family: '" + fontFamily + "'\">\n";

	for (const QStringList &cols : rows) {
		html += "<tr>\n";
		switch (cols.count()) {
			case 0:
				html += "\t<td colspan=\"2\"><hr /></td>\n";;
				break;
			case 1:
				html += "\t<td colspan=\"2\">" + cols[0].toHtmlEscaped() + "</td>\n";
				break;
			default:
				QString key = cols[0];

				bool allowHTMLValue = (key == "Config") || (key == "Data");
				QString value = allowHTMLValue ? cols[1] : cols[1].toHtmlEscaped();

				html += "\t<td><b>" + key.toHtmlEscaped() + "</b></td><td>" + value + "</td>\n";
				break;
		}
		html += "</tr>\n";
	}

	html += "</table>";

	html = Utils::makeHTML(html);

	htmlWidget->setText(html);

// DEBUG: Utils::println(html);

	largeWidget(parent, htmlWidget, i18n("System Information"), { });
}

// UMessageBuilder

// public:

bool UMessageBuilder::exec(QWidget *parent) {
	if (m_showVar && ! m_showVar->getBool())
		return true;

	auto mb = std::make_unique<QMessageBox>(parent);

	switch (m_type) {
		case Type::Error:
			mb->setIcon(QMessageBox::Critical);
			mb->setStandardButtons(QMessageBox::Ok);
			mb->setWindowTitle(i18n("Error"));
			break;
		case Type::Info:
			mb->setIcon(QMessageBox::Information);
			mb->setStandardButtons(QMessageBox::Ok);
			mb->setWindowTitle(i18n("Information"));
			break;
		case Type::Warning:
			mb->setIcon(QMessageBox::Warning);
			mb->setStandardButtons(QMessageBox::Ok);
			mb->setWindowTitle(i18n("Warning"));
			break;
		case Type::Question:
			mb->setIcon(QMessageBox::Question);
			mb->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
			mb->setWindowTitle(i18n("Confirm"));
			break;
	}

	auto *okButton = mb->button(QMessageBox::Ok);

	if (! m_okText.isEmpty()) {
		okButton->setText(m_okText);
	}

	if (! m_icon.isNull()) {
		int size = qApp->style()->pixelMetric(QStyle::PM_MessageBoxIconSize);
		mb->setIconPixmap(m_icon.pixmap(size));

		okButton->setIcon(m_icon);
	}

	mb->setDefaultButton(m_cancelDefault ? QMessageBox::Cancel : QMessageBox::Ok);

	mb->setTextFormat(m_textFormat);
	mb->setText(m_text);

	if (! m_title.isEmpty())
		mb->setWindowTitle(m_title);

	QCheckBox *doNotShowCheckBox;
	if (m_showVar) {
		doNotShowCheckBox = new QCheckBox(i18n("Do not show this message again"));
		mb->setCheckBox(doNotShowCheckBox);
	}
	else {
		doNotShowCheckBox = nullptr;
	}

	bool result = mb->exec() == QMessageBox::Ok;

	if ((doNotShowCheckBox != nullptr) && doNotShowCheckBox->isChecked()) {
		m_showVar->setBool(false);
		m_showVar->write();
	}

	return result;
}
