/*
    SPDX-FileCopyrightText: 2014-2023 Anne Jan Brouwer <brouwer@annejan.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 "usersdialog.h"
#include "pass.h"
#include "ui_usersdialog.h"
#include "ui_userswidget.h"
#include <QMessageBox>
#include <QRegularExpression>
#include <QWidget>
#include <utility>
#include <KI18n/KLocalizedString>

void UsersWidgetData::generateUserList()
{
    QList<UserInfo> users = m_pass.listKeys();

    QList<UserInfo> selected_users;
    int count = 0;

    QStringList recipients = m_pass.getRecipientList(m_dir);
    if (!recipients.isEmpty())
        selected_users = m_pass.listKeys(recipients);
    for (const UserInfo &sel : qAsConst(selected_users)) {
        for (auto &user : users)
            if (sel.key_id == user.key_id)
                user.enabled = true;
    }

    if (count > selected_users.size()) {
        // Some keys seem missing from keyring, add them separately
        const QStringList missingRecipients = m_pass.getRecipientList(m_dir.isEmpty() ? QString{} : m_dir);
        for (const QString &missingRecipient : qAsConst(recipients)) {
            if (m_pass.listKeys(missingRecipient).empty()) {
                UserInfo i;
                i.enabled = true;
                i.key_id = missingRecipient;
                i.name = QStringLiteral(" ?? ") + i18n("Key not found in keyring");
                users.append(i);
            }
        }
    }

    m_userList = users;
}

void UsersWidgetData::init()
{
    m_pass.Init(m_dir, m_userList);
}

void UsersWidgetData::setUi(Ui_UsersWidget *u)
{
    this->ui = u;

    QObject::connect(ui->listWidget, &QListWidget::itemChanged, ui->listWidget, [this](auto item) {
        itemChange(item);
    });
    QObject::connect(ui->checkBox, &QCheckBox::stateChanged, ui->checkBox, [this]() {
        populateList();
    });
    QObject::connect(ui->lineEdit, &QLineEdit::textChanged, ui->lineEdit, [this]() {
        populateList();
    });
}

/**
 * @brief UsersDialog::UsersDialog basic constructor
 * @param parent
 */
UsersDialog::UsersDialog(const QString& dir, Pass &pass, QWidget *parent)
    : QDialog(parent)
    , dialogUi(std::make_unique<Ui_UsersDialog>())
    , ui(std::make_unique<Ui_UsersWidget>())
    , d(pass)
{
    d.m_dir = dir;

    dialogUi->setupUi(this);
    ui->setupUi(dialogUi->widget);
    d.generateUserList();
    d.setUi(ui.get());
    if (d.m_userList.isEmpty()) {
        QMessageBox::critical(parent, i18n("Keylist missing"), i18n("Could not fetch list of available GPG keys"));
        return;
    }

    d.populateList();

    connect(dialogUi->buttonBox, &QDialogButtonBox::accepted, this, &UsersDialog::accept);
    connect(dialogUi->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);

    ui->lineEdit->setClearButtonEnabled(true);
}

/**
 * @brief UsersDialog::~UsersDialog basic destructor.
 */
UsersDialog::~UsersDialog() = default;

Q_DECLARE_METATYPE(UserInfo *)

/**
 * @brief UsersDialog::accept
 */
void UsersDialog::accept()
{
    d.init();

    QDialog::accept();
}

/**
 * @brief UsersDialog::itemChange update the item information.
 * @param item
 */
void UsersWidgetData::itemChange(QListWidgetItem *item)
{
    if (!item)
        return;
    auto *info = item->data(Qt::UserRole).value<UserInfo *>();
    if (!info)
        return;
    info->enabled = item->checkState() == Qt::Checked;
}

/**
 * @brief UsersDialog::populateList update the view based on filter options
 * (such as searching).
 * @param filter
 */
void UsersWidgetData::populateList()
{
    const auto filter = ui->lineEdit->text();
    QRegularExpression nameFilter(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*") + filter + QStringLiteral("*")),
                                  QRegularExpression::CaseInsensitiveOption);
    ui->listWidget->clear();
    if (!m_userList.isEmpty()) {
        for (auto &user : m_userList) {
            if (filter.isEmpty() || nameFilter.match(user.name).hasMatch()) {
                if (!user.isValid() && !ui->checkBox->isChecked())
                    continue;
                if (user.expiry.toSecsSinceEpoch() > 0 && user.expiry.daysTo(QDateTime::currentDateTime()) > 0 && !ui->checkBox->isChecked())
                    continue;
                QString userText = user.name + QStringLiteral("\n") + user.key_id;
                if (user.created.toSecsSinceEpoch() > 0) {
                    userText +=
                        QStringLiteral(" ") + i18nc("time of key creation","created %1", QLocale::system().toString(user.created, QLocale::ShortFormat));
                }
                if (user.expiry.toSecsSinceEpoch() > 0)
                    userText +=
                        QStringLiteral(" ") + i18nc("Time of key expiry","expires %1", QLocale::system().toString(user.expiry, QLocale::ShortFormat));
                auto *item = new QListWidgetItem(userText, ui->listWidget);
                item->setCheckState(user.enabled ? Qt::Checked : Qt::Unchecked);
                item->setData(Qt::UserRole, QVariant::fromValue(&user));
                if (user.have_secret) {
                    // item->setForeground(QColor(32, 74, 135));
                    item->setForeground(Qt::blue);
                    QFont font;
                    font.setFamily(font.defaultFamily());
                    font.setBold(true);
                    item->setFont(font);
                } else if (!user.isValid()) {
                    item->setBackground(QColor(164, 0, 0));
                    item->setForeground(Qt::white);
                } else if (user.expiry.toSecsSinceEpoch() > 0 && user.expiry.daysTo(QDateTime::currentDateTime()) > 0) {
                    item->setForeground(QColor(164, 0, 0));
                } else if (!user.fullyValid()) {
                    item->setBackground(QColor(164, 80, 0));
                    item->setForeground(Qt::white);
                }

                ui->listWidget->addItem(item);
            }
        }
    }
}
