/*
    SPDX-FileCopyrightText: 2007 Ivan Cukic <ivan.cukic+kde@gmail.com>

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

#pragma once

#include <QIcon>
#include <QPair>
#include <QSortFilterProxyModel>
#include <QStandardItem>

namespace KCategorizedItemsViewModels
{
typedef QPair<QString, QVariant> Filter;

/**
 * Abstract class that needs to be implemented and used with the ItemModel
 */
class AbstractItem : public QStandardItem
{
public:
    /**
     * Returns a localized string - name of the item
     */
    virtual QString name() const;

    /**
     * Returns a unique id related to this item
     */
    virtual QString id() const;

    /**
     * Returns a localized string - description of the item
     */
    virtual QString description() const;

    /**
     * Returns if the item is flagged as favorite
     * Default implementation checks if the item passes the Filter("favorite", "1") filter
     */
    virtual bool isFavorite() const;

    /**
     * Returns the item's number of running applets
     * Default implementation just returns 0
     */
    virtual int running() const;

    /**
     * Returns if the item contains string specified by pattern.
     * Default implementation checks whether name or description contain the
     * string (not needed to be exactly that string)
     */
    virtual bool matches(const QString &pattern) const;

    /**
     * sets the number of running applets for the item
     */
    virtual void setRunning(int count) = 0;

    /**
     * Returns if the item passes the filter specified
     */
    virtual bool passesFiltering(const Filter &filter) const = 0;

    virtual QStringList keywords() const
    {
        return {};
    };

private:
};

/**
 * The default implementation of the model containing filters
 */
class DefaultFilterModel : public QStandardItemModel
{
    Q_OBJECT
    Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
    enum Roles {
        FilterTypeRole = Qt::UserRole + 1,
        FilterDataRole = Qt::UserRole + 2,
        SeparatorRole = Qt::UserRole + 3,
    };
    explicit DefaultFilterModel(QObject *parent = nullptr);

    QHash<int, QByteArray> roleNames() const override;

    /**
     * Adds a filter to the model
     * @param caption The localized string to be displayed as a name of the filter
     * @param filter The filter structure
     * @param icon The filter icon
     */
    void addFilter(const QString &caption, const Filter &filter, const QIcon &icon = QIcon());

    /**
     * Adds a separator to the model
     * @param caption The localized string to be displayed as a name of the separator
     */
    void addSeparator(const QString &caption);

    int count()
    {
        return rowCount(QModelIndex());
    }

    Q_INVOKABLE QVariantHash get(int i) const;

Q_SIGNALS:
    void countChanged();
};

/**
 * Default filter proxy model.
 */
class DefaultItemFilterProxyModel : public QSortFilterProxyModel
{
    Q_OBJECT
    Q_PROPERTY(QString searchTerm READ searchTerm WRITE setSearchTerm NOTIFY searchTermChanged)
    Q_PROPERTY(QString filterType READ filterType WRITE setFilterType NOTIFY filterChanged)
    Q_PROPERTY(QVariant filterQuery READ filterQuery WRITE setFilterQuery NOTIFY filterChanged)
    Q_PROPERTY(int count READ count NOTIFY countChanged)

public:
    explicit DefaultItemFilterProxyModel(QObject *parent = nullptr);

    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
    bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;

    void setSearchTerm(const QString &pattern);
    QString searchTerm() const;

    void setFilterType(const QString &type);
    QString filterType() const;

    void setFilterQuery(const QVariant &query);
    QVariant filterQuery() const;

    void setFilter(const Filter &filter);

    void setSourceModel(QAbstractItemModel *sourceModel) override;

    QAbstractItemModel *sourceModel() const;

    int columnCount(const QModelIndex &index) const override;

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

    int count()
    {
        return rowCount(QModelIndex());
    }

    Q_INVOKABLE QVariantHash get(int i) const;

Q_SIGNALS:
    void searchTermChanged(const QString &term);
    void filterChanged();
    void countChanged();

private:
    Filter m_filter;
    QString m_searchPattern;
};

} // end of namespace
