#ifndef DATABASE_H
#define DATABASE_H

#include "types.h"
#include <QObject>
#include <QSqlDatabase>
#include <QSettings>

class DataBase : public QObject
{
    Q_OBJECT
public:
    explicit DataBase(QObject *parent = nullptr);
    ~DataBase();

    enum ItemType {
        Icon = 1,
        Group,
        Container,
        Widget
    };

    ///
    /// \brief openDatabase：打开数据库
    /// \return 成功 or 失败
    ///
    bool openDatabase();
    ///
    /// \brief 关闭数据库
    ///
    void closeDataBase();

public:
    ///
    /// \brief getIdleItemID：获取未被使用的 item 的 ID
    /// \return
    ///
    quint32 getIdleItemID();
    ///
    /// \brief queryAllItemData：查询系统中全部的 Item 数据
    /// \warning 注意指针数组一定要进行释放
    /// \return 存储所有应用指针的map
    ///
    QMap<quint32, UKUI::BaseItem *> queryAllItemData();
    ///
    /// \brief queryAllSetData：查询可以翻页的 Sets 中全部的 Item 数据
    /// \return 存储 Sets 中所有的 Item 指针 <setId, <Set第一页的idlist，Set第二页的idlist>>
    ///
    QMap<quint32, QList<QList<quint32>>> queryAllFlipSetData();

    ///
    /// \brief queryAllScrollSetData：查询可以滚动的 Sets 中全部的 Item 数据
    /// \return
    ///
    QMap<quint32, QList<quint32>> queryAllScrollSetData();
    ///
    /// \brief queryAllPageData：查询 Page 中全部的 Item 数据
    /// \return 存储 Page 中所有的 Item 指针 <pageId, <itemId>>
    ///
    QMap<quint32, QList<quint32>> queryAllPageData();
    ///
    /// \brief queryItemDataFromID：根据 ID 查询全部 Item 数据
    /// \param id：应用的 id
    ///
    void queryItemDataFromID(int id);
    ///
    /// \brief querySetDataFromID：根据 ID 查询Set的数据
    /// \param id
    ///
    QList<quint32> querySetDataFromID(int id);
    ///
    /// \brief queryPageDataFromID：根据 ID 查询第 page 页的数据
    /// \param pageId：page 页的 id
    /// \return pageId 页的所有 item
    ///
    QList<quint32> queryPageDataFromID(int pageId);
    ///
    /// \brief queryIdFromDesktopName：根据 desktop 名字查询 id
    /// \param desktopName：应用的 desktop 名字
    /// \return 应用的 id
    ///
    quint32 queryIdFromDesktopName(QString desktopName);
    ///
    /// \brief addItem：在数据库中插入 Item 对象
    /// \param desktopName：item的 desktop 名字
    /// \param name：item 的名字
    /// \param iconName：item 图标的名字
    /// \param type：item 的类型
    /// \param _placeholder：item 的占位符
    /// \param _categories：item 的分类
    /// \return
    ///
    QVariant addItem(quint32 itemId, const QString &desktopName, const QString &name, const QString &iconName, const QVariant &type,
                     const QList<quint32> &_placeholder = {1, 1}, const QList<int> &_categories = {-1});
    ///
    /// \brief addFlipSet：在数据库中添加 container 或 group 数据
    /// \param setId：可翻页的set 的 id
    /// \param sequence：set 内的应用列表
    /// \return
    ///
    QVariant addFlipSet(quint32 setId, const QList<QList<quint32>> &sequence);
    ///
    /// \brief addScrollSet：在数据库中添加 container 或 group 数据
    /// \param setId：可滚动的set 的 id
    /// \param sequence
    /// \return
    ///
    QVariant addScrollSet(quint32 setId, const QList<quint32> &sequence);
    ///
    /// \brief addPage：在数据库中添加 page 数据
    /// \param pageId：page 页的 id
    /// \param sequence：page 内的应用列表
    ///
    bool addPage(quint32 pageId, const QList<quint32> &sequence);
    ///
    /// \brief modifyItemData：修改应用的数据
    /// \param id：应用 id
    /// \param desktopName：应用的 desktop 名字
    /// \param name：应用显示的名字
    /// \param iconName：应用图标的名字
    /// \param _categories：应用的分类
    ///
    bool modifyItemData(quint32 id, const QString &desktopName, const QString &name, const QString &iconName, const QList<int> &_categories);
    ///
    /// \brief setFlipSetData：修改 container 或者 group 里的应用列表
    /// \param setId：container 或 group 的 id
    /// \param sequence：应用列表
    ///
    bool setFlipSetData(quint32 setId, const QList<QList<quint32>> &sequence);

    ///
    /// \brief setScrollSetData
    /// \param setId
    /// \param sequence
    ///
    bool setScrollSetData(quint32 setId, const QList<quint32> &sequence);

    ///
    /// \brief modifySetName：修改 container 或者 group 的名字
    /// \param setId：待修改的 group/container 的id
    /// \param name：Set的名字
    /// \return true为修改成功，false修改失败
    ///
    bool modifySetName(quint32 setId, QString name);

    ///
    /// \brief setPageData   修改 page 页的数据
    /// \param pageId           page 页的 id
    /// \param sequence         page 页即将存储的应用列表
    ///
    bool setPageData(quint32 pageId, const QList<quint32> &sequence);
    ///
    /// \brief deleteBadItemListData   从列表中删除应用
    /// \param id   应用的 id
    ///
    bool deleteBadItemListData(int id);

    ///
    /// \brief updatePageItem  更新page，删除page中不存在于itemlist的id
    /// \param itemId
    ///
    bool updatePageItem();

    ///
    /// \brief updateSetItem  更新set，删除set中不存在于itemlist的id
    /// \param itemId
    ///
    bool updateSetItem();

    ///
    /// \brief deleteSetIdFromPage  删除page中存在于set的id
    /// \param itemId
    ///
    bool deleteSetIdFromPage();

    ///
    /// \brief queryItemIdFromSet 查询itemId是否在set中
    /// \param pageId
    /// \param itemId
    /// \return
    ///
    bool queryPageItemIdFromSet(int itemId);

    ///
    /// \brief queryItemIdFromList()
    /// \param itemId
    /// \return
    ///
    bool queryItemIdFromList(int itemId);
    ///
    /// \brief deleteItemListData   从列表中删除应用
    /// \param id   应用的 id
    ///
    ///
    bool deleteItemListData(int id);
    ///
    /// \brief deletePageData   删除页数据
    /// \param id   页的 id
    ///
    bool deletePageData(int id);
    ///
    /// \brief deleteSetsData   删除分组数据
    /// \param id   分组的 id
    ///
    bool deleteSetsData(int id);
    ///
    /// \brief 删除数据表
    /// \param tableName 数据表名字
    ///
    void deleteTable(const QString &tableName);

    ///
    /// \brief 删除表中所有数据
    /// \param tableName 数据表名字
    /// \return 删除成功 or 删除失败
    ///
    bool deleteTableAllData(const QString &tableName);

    ///
    /// \brief checkTables：检查所有表是否存在
    /// \return
    ///
    bool checkTables();

    ///
    /// \brief checkTablesData：校验并纠正数据表中的数据
    /// \return
    ///
    bool checkTablesData();

    ///
    /// \brief firstInit：返回firstInit的值
    /// \return
    ///
    bool getFirstInit();

private:
    ///
    /// \brief createItemsData：创建默认的 item 数据
    ///
    void createItemsData();

    ///
    /// \brief isTableExist：判断数据表是否存在
    /// \param tableName：表的名字
    /// \return 存在 or 不存在
    ///
    bool isTableExist(const QString &tableName);

signals:

private:
    QSqlDatabase db;
    quint32 idleItemId;
    bool firstInit = false;
};

#endif // DATABASE_H
