/**
 * Copyright (C) 2022 Ubports Foundation.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *  Lionel Duboeuf <lduboeuf@ouvaton.org>
 */

#include <QDebug>

#include <QtCore/QObject>
#include <QtTest/QtTest>
#include <QVariant>
#include <TelepathyQt/Contact>
#include <TelepathyQt/ContactManager>
#include <TelepathyQt/PendingContacts>
#include <TelepathyQt/PendingOperation>
#include <TelepathyQt/TextChannel>
#include <TelepathyQt/ReceivedMessage>
#include "telepathyhelper.h"
#include "ofonophonesimhelper.h"
#include "handler.h"
#include "approvertext.h"
#include "cellbroadcast-types.h"

Q_DECLARE_METATYPE(Tp::TextChannelPtr);
Q_DECLARE_METATYPE(QList<Tp::ContactPtr>);

class CellBroadcastTest : public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void initTestCase();
    void testCMASCellBroadcast();
    void testETWSCellBroadcast();
private:
    Approver *mApprover;
    Handler *mHandler;
};

void CellBroadcastTest::initTestCase()
{
    qRegisterMetaType<Tp::Presence>();
    qRegisterMetaType<Tp::TextChannelPtr>();
    qRegisterMetaType<Tp::PendingOperation*>();
    qRegisterMetaType<QList<Tp::ContactPtr> >();
    TelepathyHelper::instance();

    QSignalSpy spy(TelepathyHelper::instance(), &TelepathyHelper::accountReady);
    QTRY_COMPARE(spy.count(), 1);

    // Bring up the phonesim modem
    OfonoPhonesimHelper *phonesim = OfonoPhonesimHelper::instance();
    QTRY_COMPARE(phonesim->IsPresent(), true);
    phonesim->ModemSetOnline(true);
    QTRY_COMPARE(phonesim->NetworkRegistrationStatus(), "registered");

    // the account should be connected
    QTRY_VERIFY(TelepathyHelper::instance()->connected());

    mHandler = new Handler(this);
    TelepathyHelper::instance()->registerClient(mHandler, "TpOfonoTestHandler");
    QTRY_VERIFY(mHandler->isRegistered());

    // register the approver
    mApprover = new Approver(this);
    TelepathyHelper::instance()->registerClient(mApprover, "TpOfonoTestApprover");
    // Tp-qt does not set registered status to approvers
    QTRY_VERIFY(QDBusConnection::sessionBus().interface()->isServiceRegistered(TELEPHONY_SERVICE_APPROVER));

    // turn on CBS
    QSignalSpy spyCBS(phonesim, &OfonoPhonesimHelper::CellBroadcastPoweredUp);
    phonesim->CellBroadcastPower(true);
    QTRY_COMPARE(spyCBS.count(), 1);
}

void CellBroadcastTest::testCMASCellBroadcast()
{

    QMap<quint16, CellBroadcast::Type> channelsToTypes = {
        {25, CellBroadcast::TYPE_OTHER},
        {2360, CellBroadcast::TYPE_OTHER},
        {4370, CellBroadcast::TYPE_LEVEL_1},
        {4371, CellBroadcast::TYPE_LEVEL_2},
        {4372, CellBroadcast::TYPE_LEVEL_2},
        {4373, CellBroadcast::TYPE_LEVEL_3},
        {4374, CellBroadcast::TYPE_LEVEL_3},
        {4375, CellBroadcast::TYPE_LEVEL_3},
        {4376, CellBroadcast::TYPE_LEVEL_3},
        {4377, CellBroadcast::TYPE_LEVEL_3},
        {4378, CellBroadcast::TYPE_LEVEL_3},
        {4379, CellBroadcast::TYPE_AMBER},
        {4380, CellBroadcast::TYPE_MONTHLY_TEST},
        {4381, CellBroadcast::TYPE_EXERCISE},
        {4382, CellBroadcast::TYPE_RESERVED},
        {4398, CellBroadcast::TYPE_TEST},

    };

    QSignalSpy spy(mHandler, &Handler::textChannelAvailable);
    Q_FOREACH(quint16 channel, channelsToTypes.keys()) {
        OfonoPhonesimHelper::instance()->CellBroadcastCMASNotification("Notification message", channel);
    }

    QTRY_COMPARE(spy.count(), 1);

    Tp::TextChannelPtr channel = spy.first().first().value<Tp::TextChannelPtr>();
    QVERIFY(channel);

    QCOMPARE(channel->messageQueue().count(), channelsToTypes.count());

    for(int i=0; i < channel->messageQueue().count(); i++) {
        Tp::ReceivedMessage message = channel->messageQueue().at(i);
        QCOMPARE(message.sender()->id(), QString(CellBroadcast::CELLBROADCAST_IDENTIFIER));
        QCOMPARE(message.header().value("subject").variant().toInt(), channelsToTypes.keys().at(i));
        QCOMPARE(message.header().value(CellBroadcast::CELLBROADCAST_IDENTIFIER_TYPE).variant().toInt(), channelsToTypes.values().at(i));
        QCOMPARE(message.text(), QString("Notification message"));
        QCOMPARE(message.messageType(), Tp::ChannelTextMessageTypeNotice);
    }

    channel->requestClose();
}

void CellBroadcastTest::testETWSCellBroadcast()
{
    QList<QString> etwsTopicNames = QList<QString>() << "Earthquake" << "Tsunami" << "Earthquake+Tsunami" << "Other" << "Fake";
    QList<CellBroadcast::ETWS> expectedTopics = QList<CellBroadcast::ETWS>() << CellBroadcast::ETWS_ALERT_EARTHQUAKE << CellBroadcast::ETWS_ALERT_TSUNAMI << CellBroadcast::ETWS_ALERT_EARTHQUAKE_AND_TSUNAMI << CellBroadcast::ETWS_ALERT_OTHER << CellBroadcast::ETWS_ALERT_OTHER;
    QList<CellBroadcast::Type> expectedTopicType = QList<CellBroadcast::Type>() << CellBroadcast::TYPE_LEVEL_1 << CellBroadcast::TYPE_LEVEL_2 << CellBroadcast::TYPE_LEVEL_3;

    QSignalSpy spy(mHandler, &Handler::textChannelAvailable);


    for(int i=0; i < etwsTopicNames.count(); i++)
    {
        OfonoPhonesimHelper::instance()->CellBroadcastETWSNotification("Notification message", etwsTopicNames.at(i), true, true);
        OfonoPhonesimHelper::instance()->CellBroadcastETWSNotification("Notification message", etwsTopicNames.at(i), true, false);
        OfonoPhonesimHelper::instance()->CellBroadcastETWSNotification("Notification message", etwsTopicNames.at(i), false, false);
    }

    QTRY_COMPARE(spy.count(), 1);
    Tp::TextChannelPtr channel = spy.first().first().value<Tp::TextChannelPtr>();
    QVERIFY(channel);

    // oFono silently discards "Fake" broadcasts, so expect 3 messages missing
    QCOMPARE(channel->messageQueue().count() + 3, etwsTopicNames.count() * 3);

    for(int i=0; i < channel->messageQueue().count(); i++) {
        Tp::ReceivedMessage message = channel->messageQueue().at(i);
        QCOMPARE(message.sender()->id(), QString(CellBroadcast::CELLBROADCAST_IDENTIFIER));
        QCOMPARE(message.header().value("subject").variant().toInt(), expectedTopics.at(i / 3));
        QCOMPARE(message.header().value(CellBroadcast::CELLBROADCAST_IDENTIFIER_TYPE).variant().toInt(), expectedTopicType.at(i % 3));
        QCOMPARE(message.text(), QString("Notification message"));
        QCOMPARE(message.messageType(), Tp::ChannelTextMessageTypeNotice);
    }

    channel->requestClose();
}

QTEST_MAIN(CellBroadcastTest)
#include "CellBroadcastTest.moc"
