// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2025 Marco Martin <notmart@gmail.com>

#include "statetracker.h"
#include "keepsecret_debug.h"

#include <KLocalizedString>
#include <cstdlib>
#include <memory>

class StateTrackerSingleton
{
public:
    StateTrackerSingleton();
    std::unique_ptr<StateTracker> stateTracker;
};

StateTrackerSingleton::StateTrackerSingleton()
    : stateTracker(std::make_unique<StateTracker>())
{
}

Q_GLOBAL_STATIC(StateTrackerSingleton, s_stateTracker)

StateTracker::StateTracker(QObject *parent)
    : QObject(parent)
{
}

StateTracker::~StateTracker()
{
}

StateTracker *StateTracker::instance()
{
    return s_stateTracker->stateTracker.get();
}

StateTracker::Status StateTracker::status() const
{
    return m_status;
}

void StateTracker::setStatus(Status status)
{
    if (status == m_status) {
        return;
    }

    qCDebug(KEEPSECRET_LOG) << "Setting status" << status;

    const Status oldStatus = m_status;
    m_status = status;
    Q_EMIT statusChanged(oldStatus, status);
    if ((oldStatus & ServiceConnected) != (status & ServiceConnected)) {
        Q_EMIT serviceConnectedChanged(status & ServiceConnected);
    }
}

void StateTracker::setState(StateTracker::State state)
{
    setStatus(m_status | state);
}

void StateTracker::clearState(StateTracker::State state)
{
    setStatus(m_status & ~state);
}

bool StateTracker::isServiceConnected() const
{
    return m_status & ServiceConnected;
}

StateTracker::Operations StateTracker::operations() const
{
    return m_operations;
}

void StateTracker::setOperations(StateTracker::Operations operations)
{
    if (operations == m_operations) {
        return;
    }

    qCDebug(KEEPSECRET_LOG) << "Setting operations" << operations;

    const Operations oldOperations = m_operations;
    m_operations = operations;
    Q_EMIT operationsChanged(oldOperations, operations);
    Q_EMIT operationsReadableNameChanged(operationsReadableName());

    // If we are not saving anymore, remove ItemNeedsSave from the status
    if (!(operations & ItemSaving)) {
        setStatus(m_status & ~ItemNeedsSave);
    }
}

void StateTracker::setOperation(StateTracker::Operation operation)
{
    setOperations(m_operations | operation);
}

void StateTracker::clearOperation(StateTracker::Operation operation)
{
    // Keep the Loading or Saving flags if we still have another load/save operation
    Operations result = m_operations & ~operation;
    if (result & (ItemSavingLabel | ItemSavingSecret | ItemSavingAttributes)) {
        result |= ItemSaving;
    }
    if (result & (ItemLoadingSecret | ItemUnlocking)) {
        result |= ItemLoading;
    }
    setOperations(result);
}

QString StateTracker::operationsReadableName() const
{
    // Return a single name, regardless of the operations combination, one "wins"
    if (m_operations & ServiceConnecting) {
        return i18nc("@info:status", "Connecting");
    } else if (m_operations & ItemCreating || m_operations & CollectionCreating) {
        return i18nc("@info:status", "Creating");
    } else if (m_operations & ItemSaving) {
        return i18nc("@info:status", "Saving");
    } else if (m_operations & ItemUnlocking || m_operations & CollectionUnlocking) {
        return i18nc("@info:status", "Unlocking");
    } else if (m_operations & ItemDeleting || m_operations & CollectionDeleting) {
        return i18nc("@info:status", "Deleting");
    } else if (m_operations & CollectionLocking) {
        return i18nc("@info:status ", "Locking");
    }

    // Everything else is just "Loading"
    return i18nc("@info:status", "Loading");
}

StateTracker::Error StateTracker::error() const
{
    return m_error;
}

QString StateTracker::errorMessage() const
{
    return m_errorMessage;
}

void StateTracker::setError(StateTracker::Error error, const QString &errorMessage)
{
    if (error != NoError) {
        qCWarning(KEEPSECRET_LOG) << "ERROR:" << error << errorMessage;
    }
    if (error != m_error || errorMessage != m_errorMessage) {
        m_error = error;
        m_errorMessage = errorMessage;
        Q_EMIT errorChanged(error, errorMessage);
    }
}

void StateTracker::clearError()
{
    setError(NoError, QString());
}

#include "moc_statetracker.cpp"
