/*
 * Copyright (C) 2025 UBports Foundation.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3, as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <nmofono/wwan/ofono-nemo-slotmanager.h>

#include <QDBusError>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>

static const QString OFONO_SERVICE = QStringLiteral("org.ofono");
static const QString OFONO_NEMOMODEMMANAGER_PATH = QStringLiteral("/");

namespace nmofono
{
namespace wwan
{

OfonoNemoSlotManager::OfonoNemoSlotManager(const QDBusConnection& connection,
                                           QObject *parent)
    : QObject(parent)
    , m_dbusIntf(OFONO_SERVICE, OFONO_NEMOMODEMMANAGER_PATH, connection)
    , m_ready(false)
    , m_dataSim(nullptr)
{
    connect(&m_dbusIntf, &OrgNemomobileOfonoModemManagerInterface::ReadyChanged,
            this,        &OfonoNemoSlotManager::handleReadyChanged);

    auto call = m_dbusIntf.GetReady();
    auto watch = new QDBusPendingCallWatcher(call);
    connect(watch, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watch) {
        QDBusPendingReply<bool> reply = *watch;
        if (reply.isError()) {
            if (reply.error().type() == QDBusError::UnknownInterface) {
                qDebug() << "oFono is not a SailfishOS fork; slot manager is not used";
            } else {
                qWarning() << "Failed to get readiness status of SailfishOS slot manager:"
                           << reply.error();
            }
        } else {
            handleReadyChanged(reply.argumentAt<0>());
        }

        watch->deleteLater();
    });
}

void OfonoNemoSlotManager::handleReadyChanged(bool ready)
{
    m_ready = ready;
    setDefaultDataSimIfAppropriate();
}

void OfonoNemoSlotManager::setDataSim(const wwan::Sim::Ptr &dataSim)
{
    if (m_dataSim)
        disconnect(m_dataSim.get(), nullptr, this, nullptr);

    m_dataSim = dataSim;

    if (m_dataSim) {
        connect(dataSim.get(), &Sim::imsiChanged,
                this,          &OfonoNemoSlotManager::handleDataSimImsiChanged);
    }

    setDefaultDataSimIfAppropriate();
}

void OfonoNemoSlotManager::handleDataSimImsiChanged(const QString &)
{
    setDefaultDataSimIfAppropriate();
}

void OfonoNemoSlotManager::setDefaultDataSimIfAppropriate()
{
    if (m_ready && m_dataSim && !m_dataSim->imsi().isEmpty()) {
        qDebug().nospace()
            << "Call org.nemomobile.ofono.ModemManager."
               "SetDefaultDataSim(" << m_dataSim->imsi() << ")";

        // Asynchronous; doesn't wait for respond.
        m_dbusIntf.SetDefaultDataSim(m_dataSim->imsi());
    }
}

}
}
