/*
 * Copyright (C) 2014-2021 CZ.NIC
 *
 * This program is free software: 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include <QDesktopServices>
#include <QFileDialog>

#include "src/datovka_shared/utility/strings.h"
#include "src/global.h"
#include "src/gui/dlg_send_message.h" /* dzPrefix() */
#include "src/gui/message_operations.h"
#include "src/io/account_db.h"
#include "src/io/filesystem.h"
#include "src/io/message_db.h"
#include "src/io/message_db_set.h"
#include "src/settings/accounts.h"
#include "src/settings/prefs_specific.h"

void GuiMsgOps::exportSelectedData(const QList<MsgOrigin> &originList,
    enum Exports::ExportFileType expFileType, QWidget *parent)
{
	if (Q_UNLIKELY(originList.isEmpty())) {
		return;
	}

	/*
	 * All entries in the list may not be generated from the same account.
	 * All messages in list are downloaded here.
	 */

	/* Just take the path from the first selected message. */
	QString exportPath = PrefsSpecific::acntZfoDir(
	    *GlobInstcs::prefsPtr, originList.at(0).acntIdDb);
	QString lastPath = exportPath;
	QString errStr;

	foreach (const MsgOrigin &origin, originList) {
		if (Q_UNLIKELY(origin.msgId.dmId() < 0)) {
			Q_ASSERT(0);
			continue;
		}
		const QString dbId = GlobInstcs::accntDbPtr->dbId(
		    AccountDb::keyFromLogin(origin.acntIdDb.username()));
		const QString accountName = GlobInstcs::acntMapPtr->acntData(
		    origin.acntIdDb).accountName();

		Exports::exportAs(parent, *origin.acntIdDb.messageDbSet(),
		    expFileType, exportPath, QString(),
		    origin.acntIdDb.username(), accountName, dbId, origin.msgId,
		    true, lastPath, errStr);
		if (!lastPath.isEmpty()) {
			exportPath = lastPath;
			PrefsSpecific::setAcntZfoDir(*GlobInstcs::prefsPtr,
			    origin.acntIdDb, exportPath);
		}
	}
}

void GuiMsgOps::exportSelectedEnvelopeAndAttachments(
    const QList<MsgOrigin> &originList, QWidget *parent)
{
	if (Q_UNLIKELY(originList.isEmpty())) {
		return;
	}

	/*
	 * All entries in the list may not be generated from the same account.
	 * All messages in list are downloaded here.
	 */

	/* Just take the path from the first selected message. */
	QString newDir = QFileDialog::getExistingDirectory(parent,
	    tr("Select Directory"),
	    PrefsSpecific::acntZfoDir(*GlobInstcs::prefsPtr, originList.at(0).acntIdDb),
	    QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
	if (newDir.isEmpty()) {
		return;
	}

	QString errStr;
	foreach (const MsgOrigin &origin, originList) {
		if (Q_UNLIKELY(origin.msgId.dmId() < 0)) {
			Q_ASSERT(0);
			continue;
		}
		const QString dbId = GlobInstcs::accntDbPtr->dbId(
		    AccountDb::keyFromLogin(origin.acntIdDb.username()));
		const QString accountName = GlobInstcs::acntMapPtr->acntData(
		    origin.acntIdDb).accountName();

		Exports::exportEnvAndAttachments(
		    *origin.acntIdDb.messageDbSet(), newDir,
		    origin.acntIdDb.username(), accountName, dbId,
		    origin.msgId, errStr);

		PrefsSpecific::setAcntZfoDir(*GlobInstcs::prefsPtr,
		    origin.acntIdDb, newDir);
	}
}

QString GuiMsgOps::emailBoundary(void)
{
	return "-----" + Utility::generateRandomString(16) + "_" +
	    QDateTime::currentDateTimeUtc().toString("dd.MM.yyyy-HH:mm:ss.zzz");
}

void GuiMsgOps::createEmailWithZfos(const QList<MsgOrigin> &originList)
{
	if (Q_UNLIKELY(originList.isEmpty())) {
		return;
	}

	/*
	 * All entries in the list may not be generated from the same account.
	 * All messages in list are downloaded here.
	 */

	QString emailMessage;
	const QString boundary = emailBoundary();

	QString subject((1 == originList.size()) ?
	    tr("Data message") : tr("Data messages"));

	{
		bool first = true;
		foreach (const MsgOrigin &origin, originList) {
			if (first) {
				subject += QLatin1String(" ") +
				    QString::number(origin.msgId.dmId());
				first = false;
			} else {
				subject += QLatin1String(", ") +
				    QString::number(origin.msgId.dmId());
			}
		}
	}

	createEmailMessage(emailMessage, subject, boundary);

	foreach (const MsgOrigin &origin, originList) {
		if (Q_UNLIKELY(origin.msgId.dmId() < 0)) {
			Q_ASSERT(0);
			continue;
		}

		MessageDb *messageDb =
		    origin.acntIdDb.messageDbSet()->accessMessageDb(
		        origin.msgId.deliveryTime(), false);
		if (Q_UNLIKELY(Q_NULLPTR == messageDb)) {
			Q_ASSERT(0);
			continue;
		}

		const QByteArray base64 =
		    messageDb->getCompleteMessageBase64(origin.msgId.dmId());
		if (Q_UNLIKELY(base64.isEmpty())) {
			Q_ASSERT(0);
			continue;
		}

		QString attachName = QString("%1_%2.zfo")
		    .arg(dzPrefix(messageDb, origin.msgId.dmId()))
		    .arg(origin.msgId.dmId());
		if (Q_UNLIKELY(attachName.isEmpty())) {
			Q_ASSERT(0);
			continue;
		}

		addAttachmentToEmailMessage(emailMessage, attachName, base64,
		    boundary);
	}

	finishEmailMessage(emailMessage, boundary);

	/* Email is encoded using UTF-8. */
	QString tmpEmailFile = writeTemporaryFile(
	    TMP_ATTACHMENT_PREFIX "mail.eml", emailMessage.toUtf8());

	if (!tmpEmailFile.isEmpty()) {
		QDesktopServices::openUrl(QUrl::fromLocalFile(tmpEmailFile));
	}
}

void GuiMsgOps::createEmailWithAllAttachments(
    const QList<MsgOrigin> &originList)
{
	if (Q_UNLIKELY(originList.isEmpty())) {
		return;
	}

	/*
	 * All entries in the list may not be generated from the same account.
	 * All messages in list are downloaded here.
	 */

	QString emailMessage;
	const QString boundary = emailBoundary();

	QString subject((1 == originList.size()) ?
	    tr("Attachments of message") : tr("Attachments of messages"));

	{
		bool first = true;
		foreach (const MsgOrigin &origin, originList) {
			if (first) {
				subject += QLatin1String(" ") +
				    QString::number(origin.msgId.dmId());
				first = false;
			} else {
				subject += QLatin1String(", ") +
				    QString::number(origin.msgId.dmId());
			}
		}
	}

	createEmailMessage(emailMessage, subject, boundary);

	foreach (const MsgOrigin &origin, originList) {
		if (Q_UNLIKELY(origin.msgId.dmId() < 0)) {
			Q_ASSERT(0);
			continue;
		}

		MessageDb *messageDb =
		    origin.acntIdDb.messageDbSet()->accessMessageDb(
		        origin.msgId.deliveryTime(), false);
		if (Q_UNLIKELY(Q_NULLPTR == messageDb)) {
			Q_ASSERT(0);
			continue;
		}

		const QList<Isds::Document> attachList =
		    messageDb->getMessageAttachments(origin.msgId.dmId());
		if (Q_UNLIKELY(attachList.isEmpty())) {
			Q_ASSERT(0);
			return;
		}

		foreach (const Isds::Document &attach, attachList) {
			if (Q_UNLIKELY(attach.fileDescr().isEmpty() ||
			        attach.binaryContent().isEmpty())) {
				Q_ASSERT(0);
				continue;
			}

			addAttachmentToEmailMessage(emailMessage,
			    attach.fileDescr(), attach.base64Content().toUtf8(),
			    boundary);
		}
	}

	finishEmailMessage(emailMessage, boundary);

	QString tmpEmailFile = writeTemporaryFile(
	    TMP_ATTACHMENT_PREFIX "mail.eml", emailMessage.toUtf8());

	if (!tmpEmailFile.isEmpty()) {
		QDesktopServices::openUrl(QUrl::fromLocalFile(tmpEmailFile));
	}
}
