/**************************************************************************
** Piperka Client
** Copyright (C) 2019  Kari Pahula
**
** This program 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; either version 2 of the License, or
** (at your option) any later version.
**
** This program 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, write to the Free Software Foundation, Inc.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
**************************************************************************/

#include "comic.h"

#include <QTextStream>

ComicModel::ComicModel(QObject *parent)
    : QAbstractListModel(parent)
{
    emit downloadComicsListPrepare();
    connect(this, &ComicModel::downloadComicsListPrepare, this,
            [=]() {
        toAdd.clear();
        pendingSubscriptions.clear();
        pendingSubscriptionRefresh.clear();
        loadPending = true;
        syncPending = true;
    });
}

static const QVector<int> subscriptionModels = {ComicModel::SubscribedRole, ComicModel::UnreadCountRole};

void ComicModel::newSubscription(const QPointer<Subscription> &subscription)
{
    if (loadPending || syncPending)
        pendingSubscriptions.insert(subscription->cid(), subscription);
    else
        setSubscription(subscription);
}

void ComicModel::refreshSubscription(const QPointer<Subscription> &subscription)
{
    pendingSubscriptionRefresh.append(subscription);
}

void ComicModel::pendingSubscriptionsComplete()
{
    syncPending = false;
    finishComicsListSync();
}

void ComicModel::setSubscription(const QPointer<Subscription> &subscription)
{
    int cid = subscription->cid();
    int row = cid_row.value(cid);
    if (row > 0) {
        m_comics[row-1].setSubscription(subscription);
        QModelIndex index = createIndex(row-1, 0);
        emit dataChanged(index, index, subscriptionModels);
        connect(&(*subscription), &Subscription::unsubscribing,
                this, &ComicModel::subscriptionDeleted);
    }
}

int ComicModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_comics.count();
}

QVariant ComicModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= m_comics.count())
        return QVariant();

    const Comic &comic = m_comics[index.row()];
    if (role == CidRole)
        return comic.cid();
    else if (role == TitleRole)
        return comic.title();
    else if (role == NSFWRole)
        return comic.nsfw();
    else if (role == NativeOrderRole)
        return comic.nativeOrder();
    else if (role == SubscribedRole)
        return !comic.subscription().isNull();
    else if (role == UnreadCountRole)
        return !comic.subscription().isNull() ? comic.subscription()->num() : QVariant();
    return QVariant();
}

void ComicModel::downloadComicsListComplete(const QJsonDocument &doc)
{
    QJsonArray array = doc.array();
    int i = 1;
    for (QJsonArray::const_iterator iter = array.constBegin(); iter != array.constEnd(); ++iter) {
        QJsonArray val = (*iter).toArray();
        toAdd.append(new Comic(i++, val[0].toInt(), val[1].toString(), val.at(2).toInt() == 1));
    }

    loadPending = false;
    finishComicsListSync();
}

void ComicModel::downloadComicsListUnchanged()
{
    loadPending = false;
    finishComicsListSync();
}

void ComicModel::subscriptionDeleted()
{
    Subscription *subs = qobject_cast<Subscription *>(sender());
    int cid = subs->cid();
    if (cid == -1)
        return;
    int row = cid_row.value(cid);
    if (row) {
        connect(subs, &QObject::destroyed, this,
                [=]() {
            QModelIndex index = createIndex(row-1, 0);
            emit dataChanged(index, index, subscriptionModels);
        });
    }
}

QHash<int, QByteArray> ComicModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[CidRole] = "cid";
    roles[TitleRole] = "title";
    roles[NSFWRole] = "nsfw";
    roles[SubscribedRole] = "subscribed";
    roles[NativeOrderRole] = "native_order";
    roles[UnreadCountRole] = "unread_count";
    return roles;
}


void ComicModel::finishComicsListSync()
{
    if (!loadPending && !syncPending) {
        if (toAdd.empty()) {
            foreach(QPointer<Subscription> subs, pendingSubscriptions.values()) {
                setSubscription(subs);
            }
        } else {
            foreach(QPointer<Subscription> subs, pendingSubscriptionRefresh) {
                pendingSubscriptions.insert(subs->cid(), subs);
            }

            beginResetModel();
            m_comics.clear();
            endResetModel();

            beginInsertRows(QModelIndex(), rowCount(), rowCount());
            for (QVector<Comic *>::iterator iter = toAdd.begin(); iter != toAdd.end();) {
                QPointer<Subscription> subs = pendingSubscriptions.take((*iter)->cid());
                if (!subs.isNull()) {
                    (*iter)->setSubscription(subs);
                    connect(&(*subs), &Subscription::unsubscribing,
                            this, &ComicModel::subscriptionDeleted);
                }
                m_comics << **(iter++);
            }
            endInsertRows();
            cid_row.clear();
            for (int i = 0; i < m_comics.count(); ++i) {
                cid_row.insert(m_comics[i].cid(), i+1);
            }
        }

    }
}

void Comic::setSubscription(const QPointer<Subscription> subscription)
{
    mSubscription = subscription;
}
