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

#include "udialog.h"
#include "utils.h"
#include "uwidgets.h"

#include <QCompleter>
#include <QDebug>
#include <QPushButton>
#include <QRegularExpression>

// public:

UCommandEdit::UCommandEdit()
	: QWidget() {

	m_commandEdit = new QLineEdit();
	m_commandEdit->setClearButtonEnabled(true);

	auto *testButton = new QPushButton(i18n("Test"));
	testButton->setToolTip(i18n("Run this command"));
	connect(testButton, &QPushButton::clicked, [this]() {
		testCommand();
	});

	m_commandLabel = Utils::newLabel("<?>", m_commandEdit);

	UWidgets::newVBoxLayout(
		this,
		{
			m_commandLabel,
			UWidgets::newHBoxLayout({ m_commandEdit, testButton }, 20_px)
		},
		UWidgets::STYLE_SPACING
	);
}

void UCommandEdit::setCompleter(const QList<QString> &commands) {
	auto *completer = new QCompleter(commands, this);
	completer->setCaseSensitivity(Qt::CaseInsensitive);
	completer->setFilterMode(Qt::MatchContains);
	m_commandEdit->setCompleter(completer);
}

void UCommandEdit::setExample(const QString &value) {
	m_commandEdit->setToolTip(
		i18n("Examples:") + "\n" +
		"\n" +
		value
	);
}

// private:

void UCommandEdit::testCommand() {
	UMessageBuilder confirm(UMessageBuilder::Type::Question);
	confirm.okText(i18n("Run"));
	confirm.showKey("KShutdown Test Command");
	confirm.plainText(i18n("Are you sure?"));

	if (confirm.exec(this)) {
		QString s = command();

		if (! Utils::runSplitCommand(s)) {
			QStringList list = QProcess::splitCommand(s);
			list.replaceInStrings(QRegularExpression("^(.*)$"), "\"\\1\"");

			UMessageBuilder message(UMessageBuilder::Type::Error);
			message.plainText(i18n("Command failed to start") + "\n\n" + list.join(" "));
			message.showKey("KShutdown Test Command Error");
			message.exec(this);
		}
	}
}

// public:

// A label widget with both icon and text

// NOTE: moved from ulabel.cpp
ULabel::ULabel(QWidget *parent)
	: QFrame(parent) {

	m_iconLabel = new QLabel();
	m_textLabel = new QLabel();

	auto *layout = UWidgets::newHBoxLayout(
		this,
		{ m_iconLabel, m_textLabel },
		0_px, 0_px
	);
	layout->addStretch();
}

QHBoxLayout *ULabel::labelLayout() {
	return dynamic_cast<QHBoxLayout *>(layout());
}

void ULabel::setIcon(const QIcon &value, const int size) {
	if (value.isNull()) {
		m_iconLabel->hide();
		m_iconLabel->setPixmap(QPixmap());
	}
	else {
		m_iconLabel->show();
		m_iconLabel->setPixmap(value.pixmap(size));
	}
}

void ULabel::setIcon(const QString &iconName, const int size) {
	setIcon(QIcon::fromTheme(iconName), size);
}

void ULabel::setIcon(const QStyle::StandardPixmap standardIcon, const int size) {
	setIcon(QApplication::style()->standardIcon(standardIcon), size);
}

void ULabel::setText(const QString &value) {
	m_textLabel->setText(value);
}

void ULabel::setMarginAndSpacing(const int margin, const int spacing) {
	//qDebug() << labelLayout()->contentsMargins();
	//qDebug() << labelLayout()->spacing();
	Utils::setMargin(labelLayout(), margin);
	labelLayout()->setSpacing(spacing);
}

// public:

QIcon UWidgets::emptyIcon(const QSize &size) {
	if (size.isEmpty())
		return QIcon();

	QPixmap pixmap(size);
	pixmap.fill(QColorConstants::Transparent);

	return QIcon(pixmap);
}

bool UWidgets::isIconThemeSupported() {
	#ifdef Q_OS_WIN32
// TODO: Qt 6.x/Windows 1x
	return false;
	#else
	return true;
	#endif // Q_OS_WIN32
}

QString UWidgets::makeHTMLTable(QTextEdit *widget, const QList<QStringList> &rows) {
	QString html = "";

	auto palette = widget->palette();

	const QColor &bg = palette.color(QPalette::Base);
	const QColor &bg2 = palette.color(QPalette::AlternateBase);
// DEBUG: const QColor &bg2 = Qt::gray;
	const QColor &fg = palette.color(QPalette::Text);

// TODO: common code #api
	auto linkFG = Utils::isDark(widget) ? QColorConstants::Svg::lightskyblue : QColorConstants::Svg::royalblue;

	html += QString(R"(<style>
a {
	color: %1;
	text-decoration: none;
}
</style>)").arg(linkFG.name());
	html += "\n";

	// BUG: Bold font weight is ignored in some monospaced fonts #linux
	//      until you manually remove ",Book" (or similar) from ~/.config/kdeglobals
	//      https://bugs.kde.org/show_bug.cgi?id=378523

	// HACK: CSS "monospace" font is undefined in Qt...
	QString fontFamily = Utils::getMonospaceFontName();
	html += "<table cellspacing=\"0\" cellpadding=\"1\" style=\"background-color: " + bg.name() + "; color: " + fg.name() + "; font-family: '" + fontFamily + "'; font-size: large\">\n";

	int rowNum = 1;

	for (const QStringList &cols : rows) {
		html += "<tr>\n";

		if (cols.isEmpty()) {
			rowNum = 0; // reset
			html += "\t<td colspan=\"2\"><hr /></td>\n";;

			continue; // for
		}

		QString value = (cols.count() == 2) ? cols[1] : cols[0];

		bool isHeader = value.contains(CELL_HEADER);

		if (isHeader) {
			rowNum = 1; // reset
			value.remove(CELL_HEADER);
		}

		if (value.contains(CELL_HTML)) {
			value.remove(CELL_HTML);
			// no HTML escape
		}
		else {
			value = value.toHtmlEscaped();
		}

		QString rowStyle = ((rowNum % 2) == 0) && ! isHeader
			? "background-color: " + bg2.name()
			: "";
		rowNum++;

		if (cols.count() == 2) {
			QString key = cols[0].toHtmlEscaped();
			html += "\t<td style=\"" + rowStyle + "\"><b>" + key + "</b></td>";
			html += "<td style=\"" + rowStyle + "\">" + value + "</td>\n";
		}
		else {
			QString headerStyle = "";
			if (isHeader) {
				headerStyle = "padding-top: 1em; padding-bottom: 0.5em";
				value = "<h2>" + value + "</h2>";
			}

			html += "\t<td colspan=\"2\" style=\"" + rowStyle + "; " + headerStyle + "\">" + value + "</td>\n";
		}

		html += "</tr>\n";
	}

	html += "</table>\n";

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

	return html;
}

QHBoxLayout *UWidgets::newHBoxLayout(QWidget *parent, const QList<QObject *> &list, const int spacing, const int margin) {
	auto *result = new QHBoxLayout(parent);
	initBoxLayout(result, list, spacing, margin);

	return result;
}

QVBoxLayout *UWidgets::newVBoxLayout(QWidget *parent, const QList<QObject *> &list, const int spacing, const int margin) {
	auto *result = new QVBoxLayout(parent);
	initBoxLayout(result, list, spacing, margin);

	return result;
}

QTextEdit *UWidgets::newHTMLTableView(const QList<QStringList> &rows) {
	auto *widget = Utils::newHTMLView();
	QString html = makeHTMLTable(widget, rows);
	widget->setText(Utils::makeHTML(html));

	return widget;
}

QAction *UWidgets::newLinkAction(const QString &text, const QString &url) {
	auto *action = new QAction(text);
	action->setToolTip(url);

	QObject::connect(action, &QAction::triggered, [url]() {
		Utils::openInExternalApp(url);
	});

	return action;
}

QPushButton *UWidgets::newLinkButton(const QString &text, const QString &url) {
	auto *button = new QPushButton(text);
	button->setToolTip(url);

	QObject::connect(button, &QPushButton::clicked, [url]() {
		Utils::openInExternalApp(url);
	});

	return button;
}

// private:

void UWidgets::initBoxLayout(QBoxLayout *layout, const QList<QObject *> &list, const int spacing, const int margin) {
	if (margin != STYLE_MARGIN)
		Utils::setMargin(layout, margin);

	if (spacing != STYLE_SPACING)
		layout->setSpacing(spacing);

	for (const auto &i : list) {
		QLayout *l = dynamic_cast<QLayout *>(i);
		if (l != nullptr) {
			layout->addLayout(l);
		}
		else {
			QWidget *w = dynamic_cast<QWidget *>(i);
			if (w != nullptr) {
				layout->addWidget(w);
			}
			else {
				qCritical() << "Unsupported box layout item:" << i;
			}
		}
	}
}
