#include "keepassunlockdialog.h"
#include "signetapplication.h"

#include "core/Database.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QFileDialog>
#include <QCheckBox>

#include <format/KeePass2Reader.h>
#include <keys/PasswordKey.h>
#include <keys/FileKey.h>
#include <core/Database.h>
#include <core/Group.h>
#include <core/Entry.h>
#include <cli/Utils.h>

#include "style.h"

KeePassUnlockDialog::KeePassUnlockDialog(QFile *file, QWidget *parent) :
	QDialog(parent),
        m_keePassDatabase(NULL),
	m_databaseFile(file)
{
	QVBoxLayout *top = new QVBoxLayout();
	top->setAlignment(this, Qt::AlignTop);
	QPushButton *okay = new QPushButton("Ok");
	QPushButton *cancel = new QPushButton("Cancel");
	QHBoxLayout *password = new QHBoxLayout();
	QHBoxLayout *keyFile = new QHBoxLayout();
	QHBoxLayout *buttons = new QHBoxLayout();
	m_warnLabel = new errorText("Database read failed");
	m_warnLabel->hide();

	m_passwordCheckBox = new QCheckBox("Password");
	m_passwordCheckBox->setChecked(false);
	m_keyFileCheckBox = new QCheckBox("Key file");
	m_keyFileCheckBox->setChecked(false);
	m_passwordEdit = new QLineEdit();
	m_passwordEdit->setEchoMode(QLineEdit::Password);
	m_keyPathEdit = new QLineEdit();
	m_keyPathBrowse = new QPushButton("Browse");
	password->addWidget(m_passwordCheckBox);
	password->addWidget(m_passwordEdit);
	keyFile->addWidget(m_keyFileCheckBox);
	keyFile->addWidget(m_keyPathEdit);
	keyFile->addWidget(m_keyPathBrowse);
	buttons->addWidget(okay);
	buttons->addWidget(cancel);
	top->addWidget(new QLabel("Enter password and/or key file to read database"));
	top->addLayout(password);
	top->addLayout(keyFile);
	top->addWidget(m_warnLabel);
	top->addLayout(buttons);

	connect(m_passwordCheckBox, SIGNAL(toggled(bool)),
		this, SLOT(passwordCheckBoxToggled(bool)));
	connect(m_keyFileCheckBox, SIGNAL(toggled(bool)),
		this, SLOT(keyFileCheckBoxToggled(bool)));
	connect(m_passwordEdit, SIGNAL(textEdited(QString)),
		this, SLOT(passwordTextEdited()));
	connect(m_keyPathEdit, SIGNAL(textEdited(QString)),
		this, SLOT(keyFileTextEdited()));
	connect(okay, SIGNAL(pressed()),
		this, SLOT(okayPressed()));
	connect(cancel, SIGNAL(pressed()),
		this, SLOT(cancelPressed()));
	connect(m_keyPathBrowse, SIGNAL(pressed()),
		this, SLOT(keyPathBrowse()));
	setLayout(top);
}

void KeePassUnlockDialog::okayPressed()
{
	KeePass2Reader *r = new KeePass2Reader();
	auto k = QSharedPointer<CompositeKey>::create();
	QString password = m_passwordEdit->text();
	if (m_passwordCheckBox->isChecked()) {
		k->addKey(QSharedPointer<PasswordKey>::create(password));
	}
	QString keyPath = m_keyPathEdit->text();
	if (m_keyFileCheckBox->isChecked()) {
		auto f = QSharedPointer<FileKey>::create();
		if (!Utils::loadFileKey(keyPath, f)) {
			k->addKey(f);
		} else {
			SignetApplication::messageBoxError(QMessageBox::Warning,
			                                   windowTitle(),
			                                   "Key file invalid",
			                                   this);
			m_keyFileCheckBox->setChecked(false);
			m_keyPathEdit->setText("");
			return;
		}
	}
	m_databaseFile->reset();
	if (m_keePassDatabase)
		delete m_keePassDatabase;
	m_keePassDatabase = new Database();
	bool success = r->readDatabase(m_databaseFile, k, m_keePassDatabase);
	if (!success || !m_keePassDatabase) {
		if (r->hasError()) {
			m_warnLabel->setText("Database read failed: " + r->errorString());
		}
		m_warnLabel->show();
	} else {
		done(0);
	}
}

void KeePassUnlockDialog::cancelPressed()
{
	done(1);
}

void KeePassUnlockDialog::keyPathBrowse()
{
	QFileDialog fd(this);
	fd.setAcceptMode(QFileDialog::AcceptOpen);
	fd.setFileMode(QFileDialog::AnyFile);
	fd.exec();
	QStringList fl;
	fl = fd.selectedFiles();
	if (fl.size()) {
		m_keyPathEdit->setText(fl.at(0));
		m_keyFileCheckBox->setChecked(true);
	}
}

void KeePassUnlockDialog::passwordTextEdited()
{
	m_passwordCheckBox->setChecked(true);
}

void KeePassUnlockDialog::keyFileTextEdited()
{
	m_keyFileCheckBox->setChecked(true);
}

void KeePassUnlockDialog::passwordCheckBoxToggled(bool val)
{
	if (!val) {
		m_passwordEdit->setText("");
	}
}

void KeePassUnlockDialog::keyFileCheckBoxToggled(bool val)
{
	if (!val) {
		m_keyPathEdit->setText("");
	}
}
