/**
 * Copyright (C) 2013 Canonical, Ltd.
 *
 * 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: Tiago Salem Herrmann <tiago.herrmann@canonical.com>
 */

#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"

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

class MessagesTest : public QObject
{
    Q_OBJECT

Q_SIGNALS:
    void contactsReceived(QList<Tp::ContactPtr> contacts);

private Q_SLOTS:
    void initTestCase();
    void testMessageReceived();
    void testMessageSend();
    void testMessageSendGroupChat();

    // helper slots
    void onPendingContactsFinished(Tp::PendingOperation*);

private:
    Approver *mApprover;
    Handler *mHandler;
};

void MessagesTest::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 now
    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));
}

void MessagesTest::testMessageReceived()
{
    QSignalSpy spy(mHandler, &Handler::textChannelAvailable);

    QVERIFY(OfonoPhonesimHelper::instance()->MessageManagerSendMessage("123",
                "text"));
    QTRY_COMPARE(spy.count(), 1);

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

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

    Tp::ReceivedMessage message = channel->messageQueue().first();
    QCOMPARE(message.sender()->id(), QString("123"));
    QCOMPARE(message.text(), QString("text"));
}

void MessagesTest::testMessageSend()
{
    // Request the contact to start chatting to
    Tp::AccountPtr account = TelepathyHelper::instance()->account();
    QSignalSpy spy(this, &MessagesTest::contactsReceived);

    connect(account->connection()->contactManager()->contactsForIdentifiers(QStringList() << "321"),
            &Tp::PendingOperation::finished,
            this, &MessagesTest::onPendingContactsFinished);

    QTRY_COMPARE(spy.count(), 1);

    // Turn on Delivery Reports and send a text via text channel
    QSignalSpy spyDeliveryReport(OfonoPhonesimHelper::instance(),
            &OfonoPhonesimHelper::DeliveryReportsChanged);
    OfonoPhonesimHelper::instance()->MessageManagerUseDeliveryReports(true);
    QTRY_COMPARE(spyDeliveryReport.count(), 1);

    QList<Tp::ContactPtr> contacts = spy.first().first().value<QList<Tp::ContactPtr> >();
    QCOMPARE(contacts.count(), 1);
    QCOMPARE(contacts.first()->id(), QString("321"));

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

    Q_FOREACH(Tp::ContactPtr contact, contacts) {
        account->ensureTextChat(contact, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TpOfonoTestHandler");
    }
    QTRY_COMPARE(spyTextChannel.count(), 1);

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

    QSignalSpy spyOfonoMessageAdded(OfonoPhonesimHelper::instance(),
            &OfonoPhonesimHelper::MessageAdded);
    Tp::PendingSendMessage *message = channel->send("text");
    QTRY_COMPARE(spyOfonoMessageAdded.count(), 1);

    QTRY_COMPARE(channel->messageQueue().count(), 1);

    QVERIFY(channel->messageQueue()[0].isDeliveryReport());
    QCOMPARE(channel->messageQueue()[0].deliveryDetails().status(), Tp::DeliveryStatusAccepted);

#if 0
    // Phonesim doesn't appear to support sending status/delivery reports.
    // That is to say, it will faithfully set the TP-Status-Report-Requested
    // bit on an outgoing SMS message, but I haven't figured out a way to
    // get it to produce a status report message. In addition, I don't see
    // a delivery status signal in Ofono (though its history plugin appears
    // to have an API for it).

    QTRY_COMPARE(channel->messageQueue().count(), 2);
    QVERIFY(channel->messageQueue()[1].isDeliveryReport());
    QCOMPARE(channel->messageQueue()[1].deliveryDetails().status(), Tp::DeliveryStatusDelivered);
#endif
}

void MessagesTest::testMessageSendGroupChat()
{
    // Request the contact to start chatting to
    Tp::AccountPtr account = TelepathyHelper::instance()->account();
    QSignalSpy spy(this, &MessagesTest::contactsReceived);

    connect(account->connection()->contactManager()->contactsForIdentifiers(QStringList() << "321" << "123"),
            &Tp::PendingOperation::finished,
            this, &MessagesTest::onPendingContactsFinished);

    QTRY_COMPARE(spy.count(), 1);

    QList<Tp::ContactPtr> contacts = spy.first().first().value<QList<Tp::ContactPtr> >();
    QCOMPARE(contacts.count(), 2);
    QCOMPARE(contacts[0]->id(), QString("321"));
    QCOMPARE(contacts[1]->id(), QString("123"));

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

    account->createConferenceTextChat(QList<Tp::ChannelPtr>(), contacts, QDateTime::currentDateTime(), TP_QT_IFACE_CLIENT + ".TpOfonoTestHandler");
    QTRY_COMPARE(spyTextChannel.count(), 1);

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

    QSignalSpy spyOfonoMessageAdded(OfonoPhonesimHelper::instance(),
            &OfonoPhonesimHelper::MessageAdded);
    Tp::PendingSendMessage *message = channel->send("text");
    QTRY_COMPARE(spyOfonoMessageAdded.count(), 2);
}

void MessagesTest::onPendingContactsFinished(Tp::PendingOperation *op)
{
    Tp::PendingContacts *pc = qobject_cast<Tp::PendingContacts*>(op);
    if (!pc) {
        return;
    }

    Q_EMIT contactsReceived(pc->contacts());
}

QTEST_MAIN(MessagesTest)
#include "MessagesTest.moc"
