/*
 * Squawk messenger.
 * Copyright (C) 2019  Yury Gubich <blue@macaw.me>
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */
#pragma once

#include <map>
#include <list>
#include <functional>

#include <QXmppOmemoStorage.h>
#include <cache.h>

#include <shared/keyinfo.h>
#include <shared/enums.h>

Q_DECLARE_METATYPE(QXmppOmemoStorage::OwnDevice);
Q_DECLARE_METATYPE(QXmppOmemoStorage::Device);

namespace Core {
class Account;

class OmemoHandler : public QObject, public QXmppOmemoStorage {
    Q_OBJECT
public:
    typedef std::pair<QDateTime, QByteArray> SignedPreKeyPair;

    OmemoHandler(Account* account);
    ~OmemoHandler() override;

    virtual QXmppTask<OmemoData> allData() override;

    virtual QXmppTask<void> setOwnDevice(const std::optional<OwnDevice> &device) override;

    virtual QXmppTask<void> addSignedPreKeyPair(uint32_t keyId, const QXmppOmemoStorage::SignedPreKeyPair &keyPair) override;
    virtual QXmppTask<void> removeSignedPreKeyPair(uint32_t keyId) override;

    virtual QXmppTask<void> addPreKeyPairs(const QHash<uint32_t, QByteArray> &keyPairs) override;
    virtual QXmppTask<void> removePreKeyPair(uint32_t keyId) override;

    virtual QXmppTask<void> addDevice(const QString &jid, uint32_t deviceId, const Device &device) override;
    virtual QXmppTask<void> removeDevice(const QString &jid, uint32_t deviceId) override;
    virtual QXmppTask<void> removeDevices(const QString &jid) override;

    virtual QXmppTask<void> resetAll() override;

    bool hasOwnDevice();

    void requestBundles(const QString& jid);
    void requestOwnBundles();
    void getDevices(const QString& jid, std::list<Shared::KeyInfo>& out) const;

public slots:
    void onOmemoDeviceAdded(const QString& jid, uint32_t id);

private slots:
    void onBundlesReceived(const QString& jid);
    void onOwnBundlesReceived();
    std::list<Shared::KeyInfo> readKeys(const QString& jid);

private:
    Account* acc;
    std::optional<OwnDevice> ownDevice;
    LMDBAL::Base db;
    LMDBAL::Cache<QString, QVariant>* meta;
    LMDBAL::Cache<QString, QHash<uint32_t, Device>>* devices;
    LMDBAL::Cache<uint32_t, QByteArray>* preKeyPairs;
    LMDBAL::Cache<uint32_t, SignedPreKeyPair>* signedPreKeyPairs;
};

}

QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::Device& device);
QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::Device& device);

QDataStream& operator << (QDataStream &out, const QXmppOmemoStorage::OwnDevice& device);
QDataStream& operator >> (QDataStream &in, QXmppOmemoStorage::OwnDevice& device);