/*
 * Copyright (C) 2015 Canonical, Ltd.
 *
 * Authors:
 *  Tiago Salem Herrmann <tiago.herrmann@canonical.com>
 *
 * This file is part of lomiri-telephony-service.
 *
 * lomiri-telephony-service is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3.
 *
 * lomiri-telephony-service is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY 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 <QDebug>
#include <libintl.h>
#include <libnotify/notify.h>
#include "applicationutils.h"
#include "authhandler.h"
#include "telepathyhelper.h"

// FIXME: port to libqmenumodel if possible
AuthHandler::AuthHandler(QObject *parent)
: QObject(parent),
  mMenuNotification("authentication", false),
  mNotifications("org.freedesktop.Notifications",
                  "/org/freedesktop/Notifications", QDBusConnection::sessionBus())
{
    setupAccounts();
    connect(TelepathyHelper::instance(), SIGNAL(setupReady()), this, SLOT(setupAccounts()));
    connect(TelepathyHelper::instance(), SIGNAL(accountsChanged()), this, SLOT(setupAccounts()));
    connect(&mNotifications, SIGNAL(ActionInvoked(uint, const QString &)), this, SLOT(actionInvoked(uint, const QString &)));
    connect(&mNotifications, SIGNAL(NotificationClosed(uint, uint)), this, SLOT(notificationClosed(uint, uint)));

    connect(TelepathyHelper::instance(), &TelepathyHelper::setupReady, [&]() {
        Q_FOREACH(AccountEntry *account, TelepathyHelper::instance()->accounts()) {
            processStatusChange(account, account->account()->connectionStatus());
        }
    });
}

void AuthHandler::setupAccounts()
{
    Q_FOREACH(AccountEntry *account, TelepathyHelper::instance()->accounts()) {
        connect(account, SIGNAL(connectionStatusChanged(Tp::ConnectionStatus)), SLOT(onConnectionStatusChanged(Tp::ConnectionStatus)), Qt::UniqueConnection);
    }
}

void AuthHandler::onConnectionStatusChanged(Tp::ConnectionStatus status)
{
    AccountEntry *account = qobject_cast<AccountEntry*>(sender());
    if (!account) {
        return;
    }

    processStatusChange(account, status);
}

void AuthHandler::processStatusChange(AccountEntry *account, Tp::ConnectionStatus status)
{    
    QString title;
    QString message = QString::fromUtf8(gettext("Authentication failed. Do you want to review your credentials?"));

    if (status == Tp::ConnectionStatusDisconnected && 
            account->account()->connectionStatusReason() == Tp::ConnectionStatusReasonAuthenticationFailed &&
            !mIgnoredAccounts.contains(account->accountId())) {
        QString serviceAndDisplayName;
        QString displayName = account->displayName();
        if (displayName.isEmpty()) {
            serviceAndDisplayName = account->account()->serviceName();
        } else {
            serviceAndDisplayName = QString("%1: %2").arg(account->account()->serviceName()).arg(displayName);
        }
        title = serviceAndDisplayName;
    } else {
        return;
    }

    NotificationMenu *menu = &mMenuNotification;
    QString yesActionId = "yes_id";
    QString yesActionLabel = gettext("Yes");

    QString noActionId = "no_id";
    QString noActionLabel = gettext("No");

    QStringList actions;
    actions << yesActionId << yesActionLabel << noActionId << noActionLabel;

    // indicate to the notification-daemon, that we want to use snap-decisions
    QVariantMap notificationHints;
    notificationHints["x-lomiri-snap-decisions"] = "true";
    notificationHints["x-lomiri-private-affirmative-tint"] = "true";

    QVariantMap menuModelActions;
    menuModelActions["notifications"] = menu->actionPath();

    QVariantMap menuModelPaths;
    menuModelPaths["busName"] = menu->busName();
    menuModelPaths["menuPath"] = menu->menuPath();
    menuModelPaths["actions"] = menuModelActions;

    notificationHints["x-lomiri-private-menu-model"] = menuModelPaths;

    uint notificationId = mNotifications.Notify("lomiri-indicator-telephony-service",
                        0, "", title, message, actions, notificationHints, 0);
    mAuthFailureRequests[notificationId] = account;
}

void AuthHandler::actionInvoked(uint id, const QString &actionKey) 
{
    if (!mAuthFailureRequests.keys().contains(id)) {
        return;
    }

    if (actionKey == "yes_id") {
        ApplicationUtils::openUrl(QString("settings:///system/online-accounts"));
    } else {
        mIgnoredAccounts << mAuthFailureRequests[id]->accountId();
    }
}

void AuthHandler::notificationClosed(uint id, uint reason) {
    if (!mAuthFailureRequests.keys().contains(id)) {
        return;
    }
    mNotifications.CloseNotification(id);
    mAuthFailureRequests.remove(id);
}

void AuthHandler::clear()
{
    Q_FOREACH (uint id, mAuthFailureRequests.keys()) {
        mAuthFailureRequests.remove(id);
        mNotifications.CloseNotification(id);
    }
}
