/*
    SPDX-FileCopyrightText: 2012 Aurélien Gâteau <agateau@kde.org>
    SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#pragma once

#include "abstractmodel.h"
#include "runnermatchesmodel.h"

#include <KConfigWatcher>
#include <KRunner/QueryMatch>
#include <KSharedConfig>
#include <QAbstractListModel>
#include <QTimer>
#include <qqmlregistration.h>

class AbstractModel;

class RunnerModel : public QAbstractListModel
{
    Q_OBJECT
    QML_ELEMENT

    Q_PROPERTY(int count READ count NOTIFY countChanged)
    Q_PROPERTY(AbstractModel *favoritesModel READ favoritesModel WRITE setFavoritesModel NOTIFY favoritesModelChanged)
    Q_PROPERTY(QObject *appletInterface READ appletInterface WRITE setAppletInterface NOTIFY appletInterfaceChanged)
    Q_PROPERTY(QStringList runners READ runners WRITE setRunners NOTIFY runnersChanged)
    Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged)
    Q_PROPERTY(bool mergeResults READ mergeResults WRITE setMergeResults NOTIFY mergeResultsChanged)
    Q_PROPERTY(bool querying READ querying NOTIFY queryingChanged)
    Q_PROPERTY(bool resultsPresent READ resultsPresent NOTIFY resultsPresentChanged)

public:
    explicit RunnerModel(QObject *parent = nullptr);
    ~RunnerModel() override;

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

    QHash<int, QByteArray> roleNames() const override;
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int count() const;

    Q_INVOKABLE RunnerMatchesModel *modelForRow(int row);

    QStringList runners() const;
    void setRunners(const QStringList &runners);

    QString query() const;
    void setQuery(const QString &query);

    bool querying() const;

    AbstractModel *favoritesModel() const;
    void setFavoritesModel(AbstractModel *model);

    QObject *appletInterface() const;
    void setAppletInterface(QObject *appletInterface);

    bool mergeResults() const;
    void setMergeResults(bool merge);

    bool resultsPresent() const;

    Q_INVOKABLE void clear();

Q_SIGNALS:
    void countChanged() const;
    void favoritesModelChanged() const;
    void appletInterfaceChanged() const;
    void runnersChanged() const;
    void queryChanged() const;
    void queryFinished();
    void queryingChanged();
    void mergeResultsChanged() const;
    void resultsPresentChanged();
    void requestUpdateQuery(const QString &query);
    void anyRunnerFinished();

private Q_SLOTS:
    void startQuery();

private:
    // Initializes the models when the first query is run or mergeResults changed
    void initializeModels();
    void setEnabledRunners(const QStringList &runners);
    void updateEnabledRunners();
    void checkResultsPresent();

    AbstractModel *m_favoritesModel = nullptr;
    QObject *m_appletInterface = nullptr;
    QStringList m_runners;
    QStringList m_enabledRunners;
    QList<RunnerMatchesModel *> m_models;
    QString m_query;
    QTimer m_queryTimer;
    bool m_mergeResults;
    bool m_resultsPresent;
    int m_queryingModels = 0;
    KSharedConfigPtr m_krunnerConfig;
    KConfigWatcher::Ptr m_configWatcher;
    QStringList m_favoritePluginIds;
};
