#include "view/log/base.hpp"
#include "metatypes.hpp"
#include "util/icon.hpp"

#include <QApplication>
#include <QClipboard>
#include <QDateTime>
#include <QFileDialog>
#include <QMenu>
#include <QPushButton>
#include <QStandardPaths>
#include <QtDebug>
#include <QVBoxLayout>

Log::Base::Base(QWidget *parent)
	: QWidget(parent)
{
	auto *layout = new QVBoxLayout(this);

	list = new QTreeWidget(this);
	list->setHeaderLabels({
		QStringLiteral("Time"),
		QStringLiteral("Type"),
		QStringLiteral("Message"),
	});
	list->setEditTriggers(QAbstractItemView::NoEditTriggers);
	list->setSelectionBehavior(QAbstractItemView::SelectRows);
	list->setRootIsDecorated(false);
	list->setAllColumnsShowFocus(true);
	layout->addWidget(list, 1);

	auto *buttons = new QHBoxLayout();
	buttons->setAlignment(Qt::AlignRight);
	layout->addLayout(buttons);

	auto *copyToClipboard = new QPushButton(QStringLiteral("Copy to clipboard"), this);
	buttons->addWidget(copyToClipboard);

	QPushButton::connect(copyToClipboard, &QPushButton::clicked,
		this, &Log::Base::onCopyToClipboard);

	auto *save = new QPushButton(QStringLiteral("Save..."), this);
	buttons->addWidget(save);

	QPushButton::connect(save, &QPushButton::clicked,
		this, &Log::Base::onSaveToFile);

	list->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
	QWidget::connect(list, &QWidget::customContextMenuRequested,
		this, &Log::Base::onMenuRequested);
}

void Log::Base::showEvent(QShowEvent *event)
{
	QWidget::showEvent(event);

	list->clear();
	for (const auto &logMessage: getMessages())
	{
		const QString time = logMessage.timeString();
		const QString type = logMessage.typeLongString();
		const QString message = logMessage.message();

		auto *item = new QTreeWidgetItem({
			time,
			type,
			message,
		});

		item->setToolTip(0, time);
		item->setToolTip(1, type);
		item->setToolTip(2, message);

		item->setData(0, messageRole, QVariant::fromValue(logMessage));
		list->addTopLevelItem(item);
	}
}

auto Log::Base::collectLogs() -> QString
{
	QStringList items;

	for (auto i = 0; i < list->topLevelItemCount(); i++)
	{
		auto *item = list->topLevelItem(i);
		const auto &data = item->data(0, messageRole);
		const auto &message = data.value<LogMessage>();

		items.append(message.toString());
	}

	return items.join('\n');
}

void Log::Base::onCopyToClipboard(bool /*checked*/)
{
	QApplication::clipboard()->setText(collectLogs());
}

void Log::Base::onSaveToFile(bool /*checked*/)
{
	const auto location = QStandardPaths::DocumentsLocation;
	const auto path = QStandardPaths::standardLocations(location).first();
	const auto date = QDateTime::currentDateTime().toString("yyyyMMdd");

	const auto filename = QFileDialog::getSaveFileName(this,
		QStringLiteral("Select location"),
		QString("%1/spotify-qt-%2.log").arg(path, date),
		QStringLiteral("Logs (*.log)"));

	if (filename.isEmpty())
	{
		return;
	}

	QFile out(filename);
	if (!out.open(QIODevice::WriteOnly))
	{
		qWarning() << "Failed to open file for writing:" << out.errorString();
		return;
	}

	out.write(collectLogs().toUtf8());
	out.close();
}

void Log::Base::onMenuRequested(const QPoint &pos)
{
	auto *item = list->itemAt(pos);
	if (item == nullptr)
	{
		return;
	}

	auto *menu = new QMenu(this);

	auto *copyToClipboard = menu->addAction(Icon::get(QStringLiteral("edit-copy")),
		QStringLiteral("Copy to clipboard"));

	QAction::connect(copyToClipboard, &QAction::triggered, [item](bool /*checked*/)
	{
		const auto &data = item->data(0, messageRole);
		const auto &message = data.value<LogMessage>();

		QApplication::clipboard()->setText(message.toString());
	});

	menu->popup(list->mapToGlobal(pos));
}
