/*
    SPDX-FileCopyrightText: 2014-2023 Anne Jan Brouwer <brouwer@annejan.com>
    SPDX-FileCopyrightText: 2018 Lukas Vogel <lukedirtwalker@gmail.com>
    SPDX-FileCopyrightText: 2018 Claudio Maradonna <penguyman@stronzi.org>
    SPDX-FileCopyrightText: 2023 g10 Code GmbH
    SPDX-FileContributor: Sune Stolborg Vuorela <sune@vuorela.dk>

    SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "passworddialog.h"
#include "passentry.h"
#include "passwordgenerator.h"
#include "settings.h"
#include "ui_passworddialog.h"

#include <QFileInfo>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>

PasswordDialog::PasswordDialog(const PassEntry &passEntry, const PasswordConfiguration &passConfig, QWidget *parent)
    : QDialog(parent)
    , ui(std::make_unique<Ui::PasswordDialog>())
    , m_passEntry(passEntry)
    , m_passConfig(passConfig)
{
    ui->setupUi(this);

    load();

    setTemplate(Settings::getPassTemplate(), Settings::isUseTemplate());
    templateAll(Settings::isTemplateAllFields());

    setLength(m_passConfig.length);
    setPasswordCharTemplate(m_passConfig.selected);

    connect(ui->createPasswordButton, &QAbstractButton::clicked, this, &PasswordDialog::createPassword);
    connect(ui->createPasswordOptionsButton, &QAbstractButton::toggled, this, &PasswordDialog::togglePasswordGenerationOption);
    togglePasswordGenerationOption(false);
}

/**
 * @brief Pass{}{}wordDialog::~PasswordDialog basic destructor.
 */
PasswordDialog::~PasswordDialog() = default;

/**
 * @brief PasswordDialog::on_createPasswordButton_clicked generate a random
 * passwords.
 * @todo refactor when process is untangled from MainWindow class.
 */
void PasswordDialog::createPassword()
{
    setEnabled(false);

    const auto charset = m_passConfig.Characters[static_cast<PasswordConfiguration::characterSet>(ui->passwordTemplateSwitch->currentIndex())];
    const auto length = static_cast<unsigned int>(ui->spinBox_pwdLength->value());
    QString newPass;
    if (charset.length() > 0) {
        newPass = PasswordGenerator::generateRandomPassword(charset, length);
    } else {
        QMessageBox::critical(this,
                              i18n("No characters chosen"),
                              i18n("Can't generate password, there are no characters to choose from "
                                   "set in the configuration!"));
    }

    if (newPass.length() > 0)
        ui->lineEditPassword->setPassword(newPass);
    setEnabled(true);
}

void PasswordDialog::accept()
{
    Q_EMIT save(toRawContent());
}

/**
 * @brief PasswordDialog::setPassword populate the (templated) fields.
 * @param password
 */
void PasswordDialog::load()
{
    ui->lineEditPassword->setPassword(m_passEntry.password());

    QWidget *previous = ui->createPasswordButton;
    // first set templated values
    auto namedValues = m_passEntry.namedValues();
    for (QLineEdit *line : std::as_const(templateLines)) {
        line->setText(namedValues.takeValue(line->objectName()));
        previous = line;
    }
    // show remaining values (if there are)
    otherLines.clear();
    for (const auto &nv : std::as_const(namedValues)) {
        auto *line = new QLineEdit();
        line->setObjectName(nv.name);
        line->setText(nv.value);
        ui->formLayout->addRow(new QLabel(nv.name), line);
        setTabOrder(previous, line);
        otherLines.append(line);
        previous = line;
    }

    ui->plainTextEdit->insertPlainText(m_passEntry.remainingData());
}

QString PasswordDialog::toRawContent() const
{
    QString passFile = ui->lineEditPassword->password() + QLatin1Char('\n');
    QList<QLineEdit *> allLines(templateLines);
    allLines.append(otherLines);
    for (QLineEdit *line : allLines) {
        const QString text = line->text();
        if (text.isEmpty())
            continue;
        passFile += line->objectName() + QStringLiteral(": ") + text + QLatin1Char('\n');
    }
    passFile += ui->plainTextEdit->toPlainText();

    if (passFile.right(1) != QLatin1Char('\n'))
        passFile += QLatin1Char('\n');
    return passFile;
}

/**
 * @brief PasswordDialog::setTemplate set the template and create the fields.
 * @param rawFields
 */
void PasswordDialog::setTemplate(const QString &rawFields, bool useTemplate)
{
    m_fields = rawFields.split(QLatin1Char('\n'));
    m_templating = useTemplate;
    templateLines.clear();

    if (m_templating) {
        QWidget *previous = ui->createPasswordButton;
        for (const QString &field : std::as_const(m_fields)) {
            if (field.isEmpty())
                continue;
            auto *line = new QLineEdit();
            line->setObjectName(field);
            ui->formLayout->addRow(new QLabel(i18nc("Field name", "%1:", field)), line);
            setTabOrder(previous, line);
            templateLines.append(line);
            previous = line;
        }
    }
}

/**
 * @brief PasswordDialog::templateAll basic setter for use in
 * PasswordDialog::setPassword templating all tokenisable lines.
 * @param templateAll
 */
void PasswordDialog::templateAll(bool templateAll)
{
    m_allFields = templateAll;
}

/**
 * @brief PasswordDialog::setLength
 * PasswordDialog::setLength password length.
 * @param l
 */
void PasswordDialog::setLength(int l)
{
    ui->spinBox_pwdLength->setValue(l);
}

/**
 * @brief PasswordDialog::setPasswordCharTemplate
 * PasswordDialog::setPasswordCharTemplate chose the template style.
 * @param t
 */
void PasswordDialog::setPasswordCharTemplate(int t)
{
    ui->passwordTemplateSwitch->setCurrentIndex(t);
}

void PasswordDialog::togglePasswordGenerationOption(bool checked)
{
    if (checked) {
        ui->createPasswordOptionsButton->setIcon(QIcon::fromTheme(QStringLiteral("collapse-symbolic")));
        ui->createPasswordOptionsButton->setToolTip(i18nc("@info:tooltip", "Collapse password options"));
        ui->createPasswordOptionsButton->setAccessibleName(i18nc("@info:tooltip", "Collapse password options"));
        ui->label_characterset->setVisible(true);
        ui->passwordTemplateSwitch->setVisible(true);
        ui->label_length->setVisible(true);
        ui->spinBox_pwdLength->setVisible(true);
    } else {
        ui->createPasswordOptionsButton->setIcon(QIcon::fromTheme(QStringLiteral("expand-symbolic")));
        ui->createPasswordOptionsButton->setToolTip(i18nc("@info:tooltip", "Toggle password options"));
        ui->createPasswordOptionsButton->setAccessibleName(i18nc("@info:tooltip", "Toggle password options"));
        ui->label_characterset->setVisible(false);
        ui->passwordTemplateSwitch->setVisible(false);
        ui->label_length->setVisible(false);
        ui->spinBox_pwdLength->setVisible(false);
    }
}
