/*
    SPDX-FileCopyrightText: 2023 g10 Code GmbH
    SPDX-FileContributor: Sune Stolborg Vuorela <sune@vuorela.dk>

    SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "firsttimedialog.h"
#include "qdebug.h"

#include <QPixmap>

#include <QFileDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QProgressBar>
#include <QRegularExpressionValidator>

#include "gpgmehelpers.h"
#include "settings.h"
#include "ui_keygenwidget.h"
#include "ui_selectpasswordstore.h"
#include "ui_userswidget.h"
#include "util.h"
#include <QGpgME/KeyListJob>
#include <QGpgME/QuickJob>
#include <gpgme++/keylistresult.h>
#include <KI18n/KLocalizedString>

DialogState::DialogState(Pass &p)
    : pass(p)
{
}

QList<UserInfo> DialogState::privateKeys() const
{
    auto job = protocol->keyListJob();
    std::vector<GpgME::Key> keys;
    auto result = job->exec(QStringList(), true, keys);
    if (!isSuccess(result.error())) {
        return {};
    }
    QList<UserInfo> users;
    for (const auto &key : keys) {
        UserInfo ui;
        ui.created = QDateTime::fromTime_t(key.subkey(0).creationTime());
        ui.key_id = fromGpgmeCharStar(key.keyID());
        ui.name = createCombinedNameString(key.userID(0));
        ui.validity = key.userID(0).validityAsString();
        ui.expiry = QDateTime::fromTime_t(key.subkey(0).expirationTime());
        ui.have_secret = key.hasSecret();
        users.append(ui);
    }
    return users;
}

FirstTimeDialog::FirstTimeDialog(QWidget *mainWindow, Pass &pass)
    : m_mainWindow(mainWindow)
    , m_state(pass)
{
    setWindowTitle(i18n("GnuPG Password Manager setup"));
    setPage(Intro, new IntroPage(m_state));
    setPage(KeyGen, new KeyGenPage(m_state));
    setPage(PasswordStore, new PasswordStorePage(m_state));
    setPage(KeySelect, new KeySelectPage(m_state));
    setPage(Done, new DonePage());
    QTransform rotate;
    rotate.rotate(-90);

    setPixmap(QWizard::WatermarkPixmap, QPixmap(QLatin1String(":/artwork/gnupg-logo-320x100tr.png")).transformed(rotate));
    setPixmap(QWizard::LogoPixmap, QPixmap(QLatin1String(":/artwork/64-gpgpass.png")));

    setStartId(Intro);
}

void FirstTimeDialog::done(int i)
{
    if (i == QDialog::DialogCode::Accepted) {
        QSettings s;
        s.setValue(QStringLiteral("setup"), true);
        if (Settings::getAutoclearSeconds() < 5)
            Settings::setAutoclearSeconds(10);
        if (Settings::getAutoclearPanelSeconds() < 5)
            Settings::setAutoclearPanelSeconds(10);
        Settings::setPassTemplate(QStringLiteral("login\nurl"));
        m_mainWindow->show();
    }
    QWizard::done(i);
}

int FirstTimeDialog::nextId() const
{
    switch (currentId()) {
    case Intro:
        if (m_state.privateKeys().isEmpty()) {
            return KeyGen;
        } else {
            return PasswordStore;
        }
    case KeyGen:
        return PasswordStore;
    case PasswordStore:
        if (QFile::exists(m_state.storePath + QStringLiteral("/.gpg-id"))) {
            return Done;
        } else {
            return KeySelect;
        }
    case KeySelect:
        return Done;
    default:
        return -1;
    }

    return -1;
};

IntroPage::IntroPage(DialogState &s)
    : m_state(s)
{
    QVBoxLayout *lay = new QVBoxLayout();
    lay->addWidget(new QLabel(i18n("Welcome to GnuPG Password manager")));
    setTitle(i18n("Welcome"));
    setSubTitle(i18n("Setting up"));
    setLayout(lay);
}

KeyGenPage::KeyGenPage(DialogState &s)
    : m_state(s)
{
    setTitle(i18n("Generate keys"));
    setSubTitle(i18n("Generate keys"));
    m_ui = std::make_unique<Ui_KeyGenWidget>();
    m_ui->setupUi(this);
    m_ui->spinner->hide();
    m_ui->generateButton->setEnabled(false);
    m_ui->message->hide();
    m_ui->email->setValidator(
        new QRegularExpressionValidator(QRegularExpression(QRegularExpression::anchoredPattern(QStringLiteral(R"(\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b)")),
                                                           QRegularExpression::CaseInsensitiveOption)));
    connect(m_ui->generateButton, &QPushButton::clicked, this, &KeyGenPage::startKeyGen);
    connect(m_ui->email, &QLineEdit::textChanged, this, &KeyGenPage::checkEntries);
    connect(m_ui->name, &QLineEdit::textChanged, this, &KeyGenPage::checkEntries);
}

void KeyGenPage::startKeyGen()
{
    m_ui->email->setEnabled(false);
    m_ui->name->setEnabled(false);
    m_ui->generateButton->setEnabled(false);
    m_ui->includeComment->setEnabled(false);
    m_ui->spinner->show();

    auto job = m_state.protocol->quickJob();
    connect(job, &QGpgME::QuickJob::result, this, [this](auto &&result, const QString &log, auto &&logResult) {
        if (isSuccess(result)) {
            Q_EMIT this->completeChanged();
            this->m_ui->spinner->hide();
            this->m_ui->message->show();
            this->m_ui->message->setText(i18n("Key generated"));
        } else {
            this->m_ui->message->setText(fromGpgmeCharStar(result.asString()));
            this->m_ui->message->show();
        }
        Q_UNUSED(log);

        Q_UNUSED(logResult);
    });
    QString uid;
    if (m_ui->includeComment->isChecked()) {
        uid = QStringLiteral("%1 (PasswordManager) <%2>");
    } else {
        uid = QStringLiteral("%1 <%2>");
    }
    job->startCreate(uid.arg(m_ui->name->text(), m_ui->email->text()), "future-default");
}

void KeyGenPage::checkEntries()
{
    auto emailValidator = m_ui->email->validator();
    bool enable = false;
    if (emailValidator) {
        auto email = m_ui->email->text();
        int i = 0;
        if (emailValidator->validate(email, i) == QValidator::Acceptable) {
            qDebug() << "email valid";
            enable = m_ui->name->text().size() > 4;

        } else {
            qDebug() << "email invalid";
        }
    } else {
        qDebug() << "no email validator";
        // TODO_REMOV
        enable = true;
    }

    m_ui->generateButton->setEnabled(enable);
}

KeyGenPage::~KeyGenPage() = default;

bool KeyGenPage::isComplete() const
{
    return !m_state.privateKeys().isEmpty();
}

PasswordStorePage::PasswordStorePage(DialogState &s)
    : m_ui(std::make_unique<Ui_SelectPasswordStore>())
    , m_state(s)
{
    setTitle(i18n("Select password store"));
    setSubTitle(i18n("Folder for selection"));
    m_ui->setupUi(this);
    m_ui->lineEdit->setText(Util::findPasswordStore());
    connect(m_ui->pushButton, &QPushButton::clicked, this, [this]() {
        QFileDialog dialog(this);
        dialog.setFileMode(QFileDialog::Directory);
        dialog.setFilter(QDir::NoFilter);
        dialog.setOption(QFileDialog::ShowDirsOnly);
        QString result;
        if (dialog.exec())
            result = dialog.selectedFiles().constFirst();

        m_ui->lineEdit->setText(result);
    });
    m_ui->label->hide();
    connect(m_ui->lineEdit, &QLineEdit::textChanged, this, &PasswordStorePage::completeChanged);
    connect(m_ui->checkBox, &QCheckBox::stateChanged, this, &PasswordStorePage::completeChanged);
}

bool PasswordStorePage::isComplete() const
{
    QString dir = m_ui->lineEdit->text();
    if (QDir(dir).exists()) {
        m_ui->label->hide();
        return true;
    }
    if (m_ui->checkBox->isChecked()) {
        m_ui->label->hide();
        return true;
    }
    m_ui->label->show();
    return false;
}

bool PasswordStorePage::validatePage()
{
    m_state.storePath = Util::normalizeFolderPath(QDir::fromNativeSeparators(m_ui->lineEdit->text()));
    Settings::setPassStore(m_state.storePath);
    return QDir().mkpath(m_state.storePath);
}

PasswordStorePage::~PasswordStorePage() = default;

KeySelectPage::KeySelectPage(DialogState &s)
    : m_ui(std::make_unique<Ui_UsersWidget>())
    , m_state(s)
    , d(m_state.pass)
{
    setTitle(i18n("KeySelectPage"));
    setSubTitle(i18n("Describe users with access"));
    m_ui->setupUi(this);
    d.setUi(m_ui.get());
    connect(m_ui->listWidget, &QListWidget::itemChanged, this, &KeySelectPage::completeChanged);
}

void KeySelectPage::initializePage()
{
    d.m_dir = m_state.storePath;
    d.generateUserList();
    d.populateList();
}

bool KeySelectPage::isComplete() const
{
    for (const auto &item : std::as_const(d.m_userList)) {
        if (item.enabled) {
            return true;
        }
    }
    return false;
}

bool KeySelectPage::validatePage()
{
    d.init();
    return true;
}

KeySelectPage::~KeySelectPage() = default;

DonePage::DonePage()
{
    setTitle(i18n("Setup done"));
    setSubTitle(i18n("Thanks"));
    setFinalPage(true);
}
