// SPDX-FileCopyrightText: 2014-2023 Anne Jan Brouwer <brouwer@annejan.com>
// SPDX-FileCopyrightText: 2017 Jason A. Donenfeld <Jason@zx2c4.com>
// SPDX-FileCopyrightText: 2020 Charlie Waters <cawiii@me.com>
// SPDX-FileCopyrightText: 2023 g10 Code GmbH
// SPDX-FileContributor: Sune Stolborg Vuorela <sune@vuorela.dk>
// SPDX-FileContributor: Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: GPL-3.0-or-later

#include "passentry.h"
#include "config.h"

namespace
{
bool isLineHidden(const QString &line)
{
    return line.startsWith(QStringLiteral("otpauth://"), Qt::CaseInsensitive);
}
}

PassEntry::PassEntry()
{
}

bool PassEntry::isNull() const
{
    return m_password.isEmpty() && m_remainingData.isEmpty();
}

PassEntry::PassEntry(const QString &name, const QString &content)
    : PassEntry(name, content, Config::templateEnabled() ? Config::passTemplate() : QStringList(), Config::templateEnabled() && Config::templateAllFields())
{
}

// TODO port to QStringView once we don't need to support Qt5 anymore
PassEntry::PassEntry(const QString &name, const QString &content, const QStringList &templateFields, bool allFields)
    : m_name(name)
{
    if (content.isEmpty()) {
        return;
    }
    auto lines = content.split(QLatin1Char('\n'));
    m_password = lines.takeFirst();
    QStringList remainingData;
    QStringList remainingDataForDisplay;
    for (const QString &line : std::as_const(lines)) {
        if (line.contains(QLatin1Char(':'))) {
            int colon = line.indexOf(QLatin1Char(':'));
            const QString name = line.left(colon);
            const QString value = line.right(line.length() - colon - 1);
            if ((allFields && !value.startsWith(QStringLiteral("//"))) // if value startswith // colon is probably from a url
                || templateFields.contains(name)) {
                m_namedValues.append({name.trimmed(), value.trimmed()});
                continue;
            }
        }

        remainingData.append(line);
        if (!isLineHidden(line)) {
            remainingDataForDisplay.append(line);
        }
    }
    m_remainingData = remainingData.join(u'\n');
    m_remainingDataForDisplay = remainingDataForDisplay.join(u'\n');
}

QString PassEntry::name() const
{
    return m_name;
}

QString PassEntry::password() const
{
    return m_password;
}

PassEntry::NamedValues PassEntry::namedValues() const
{
    return m_namedValues;
}

QString PassEntry::remainingData() const
{
    return m_remainingData;
}

QString PassEntry::remainingDataForDisplay() const
{
    return m_remainingDataForDisplay;
}

PassEntry::NamedValues::NamedValues()
    : QList()
{
}

PassEntry::NamedValues::NamedValues(std::initializer_list<NamedValue> values)
    : QList(values)
{
}

QString PassEntry::NamedValues::takeValue(const QString &name)
{
    for (int i = 0; i < length(); ++i) {
        if (at(i).name == name) {
            return takeAt(i).value;
        }
    }
    return QString();
}

bool operator==(const PassEntry::NamedValue &a, const PassEntry::NamedValue &b)
{
    return a.name == b.name && a.value == b.value;
}

QDebug operator<<(QDebug debug, const PassEntry::NamedValue &entry)
{
    QDebugStateSaver saver(debug);
    debug.nospace() << '(' << entry.name << ", " << entry.value << ')';
    return debug;
}

QDebug operator<<(QDebug debug, const PassEntry &entry)
{
    QDebugStateSaver saver(debug);
    debug.nospace() << "Password Entry(name=" << entry.name() << ", password=" << entry.password() << ", values=" << entry.namedValues() << ", "
                    << entry.remainingData() << ')';
    return debug;
}
