// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef FILESORTWORKER_H
#define FILESORTWORKER_H

#include "dfmplugin_workspace_global.h"
#include "models/fileitemdata.h"
#include "groups/groupingengine.h"
#include "groups/groupedmodeldata.h"
#include "utils/fileviewsorter.h"

#include <dfm-base/interfaces/abstractgroupstrategy.h>
#include <dfm-base/dfm_global_defines.h>
#include <dfm-base/interfaces/fileinfo.h>
#include <dfm-base/interfaces/abstractdiriterator.h>
#include <dfm-base/base/application/application.h>

#include <dfm-io/denumerator.h>

#include <QObject>
#include <QDirIterator>
#include <QReadWriteLock>
#include <QMultiMap>

using namespace dfmbase;
namespace dfmplugin_workspace {
class FileSortWorker : public QObject
{
    Q_OBJECT

    enum class SortOpt : uint8_t {
        kSortOptNone = 0,
        kSortOptOnlyOrderChanged = 1,
        kSortOptOtherChanged = 2,
    };

    enum class GroupingOpt : uint8_t {
        kGroupingOptNone = 0,
        kGroupingOptOnlyOrderChanged = 1,
        kGroupingOptOtherChanged = 2,
    };

    enum class InsertOpt : uint8_t {
        kInsertOptAppend = 0,
        kInsertOptReplace = 1,
        kInsertOptForce = 2,
    };

    enum class SortScenarios : uint8_t {
        kSortScenariosIteratorAddFile = 1,   // Iterator adding new files for sorting
        kSortScenariosIteratorExistingFile = 2,   // Iterator handling existing files in display model
        kSortScenariosNormal = 3,   // Normal display completion scenario
        kSortScenariosWatcherAddFile = 4,   // File watcher detected file addition (including rename)
        kSortScenariosWatcherOther = 5,   // Other file watcher scenarios
    };

    enum class ModelChangeType {
        // normal
        kInsertRows,
        kInsertFinished,
        kRemoveRows,
        kRemoveFinished,
        // group
        kInsertGroupRows,
        kInsertGroupFinished,
        kRemoveGroupRows,
        kRemoveGroupFinished
    };

public:
    explicit FileSortWorker(const QUrl &url,
                            const QString &key,
                            FileViewFilterCallback callfun = nullptr,
                            const QStringList &nameFilters = QStringList(),
                            const QDir::Filters filters = QDir::NoFilter,
                            QObject *parent = nullptr);
    ~FileSortWorker();
    SortOpt setSortArguments(const Qt::SortOrder order, const dfmbase::Global::ItemRoles sortRole,
                             const bool isMixDirAndFile);
    GroupingOpt setGroupArguments(const Qt::SortOrder order, const QString &strategy,
                                  const QVariantHash &expandStates);

    int childrenCount();
    int getFileItemCount();
    int getGroupItemCount();
    QVariant groupHeaderData(const int index, const int role);
    FileItemDataPointer childData(const int index);
    FileItemDataPointer childData(const QUrl &url);
    void setRootData(const FileItemDataPointer data);
    FileItemDataPointer rootData() const;
    void cancel();
    int getChildShowIndex(const QUrl &url);
    QList<QUrl> getChildrenUrls();

    DFMGLOBAL_NAMESPACE::ItemRoles getSortRole() const;
    Qt::SortOrder getSortOrder() const;
    QString getGroupStrategyName() const;
    Qt::SortOrder getGroupOrder() const;

    // 只有在没有启动sort线程时才能调用，线程启动成功了，发送信号处理
    void setTreeView(const bool isTree);
    bool currentIsGroupingMode() const;

signals:
    // NOTE: 添加以下 Group 重复信号的原因是为了防止死循环
    void insertGroupRows(int first, int count);
    void insertGroupFinish();
    void removeGroupRows(int first, int count);
    void removeGroupFinish();
    void insertRows(int first, int count);
    void insertFinish();
    void removeRows(int first, int count);
    void removeFinish();

    void requestFetchMore();
    void selectAndEditFile(const QUrl &url);
    void dataChanged(int first, int last);

    void requestSetIdel(int visiableCount, int totalCount);
    void updateRow(int row);

    void requestUpdateView();
    void requestCursorWait();
    void requestCloseCursor();

    // Grouping-related signals
    void groupDataChanged();
    void groupingFinished();   // 分组操作完成信号
    void groupExpansionChanged(const QString &strategy, const QString &key, bool state);

    // Note that the slot functions here are executed in asynchronous threads,
    // so the link can only be Qt:: QueuedConnection,
    // which cannot be directly called elsewhere, but can only be triggered by signals
signals:
    void requestSortByMimeType();
    void aboutToSwitchToListView(const QList<QUrl> &allShowList);

public slots:
    // Receive all local files of iteration of iterator thread, perform filtering and sorting
    void handleIteratorLocalChildren(const QString &key,
                                     const QList<SortInfoPointer> children,
                                     const DFMIO::DEnumerator::SortRoleCompareFlag sortRole,
                                     const Qt::SortOrder sortOrder,
                                     const bool isMixDirAndFile,
                                     bool isFirstBatch = false);
    void handleIteratorChildren(const QString &key, const QList<SortInfoPointer> children, const QList<FileInfoPointer> infos, bool isFirstBatch = false);
    void handleIteratorChildrenUpdate(const QString &key, const QList<SortInfoPointer> children, bool isFirstBatch = false);
    void handleTraversalFinish(const QString &key, bool noDataProduced = false);
    void handleSortDir(const QString &key, const QUrl &parent);

    void handleFilters(QDir::Filters filters);
    void HandleNameFilters(const QStringList &filters);
    void handleFilterData(const QVariant &data);
    void handleFilterCallFunc(FileViewFilterCallback callback);

    void onToggleHiddenFiles();
    void onShowHiddenFileChanged(bool isShow);

    void handleWatcherAddChildren(const QList<SortInfoPointer> &children);
    void handleWatcherRemoveChildren(const QList<SortInfoPointer> &children);
    bool handleWatcherUpdateFile(const SortInfoPointer child);
    void handleWatcherUpdateFiles(const QList<SortInfoPointer> &children);
    void handleWatcherUpdateHideFile(const QUrl &hidUrl);

    void handleResort(const Qt::SortOrder order, const Global::ItemRoles sortRole, const bool isMixDirAndFile);
    void handleReGrouping(const Qt::SortOrder order, const QString &strategy, const QVariantHash &expansionStates);
    void onAppAttributeChanged(Application::ApplicationAttribute aa, const QVariant &value);

    bool handleUpdateFile(const QUrl &url);
    void handleUpdateFiles(const QList<QUrl> &urls);

    void handleRefresh();
    void handleClearThumbnail();
    void handleFileInfoUpdated(const QUrl &url, const QString &infoPtr, const bool isLinkOrg);
    void handleUpdateRefreshFiles();
    void handleSortByMimeType();

    void handleAboutToInsertFilesToGroup(int pos, int count);
    void handleAboutToRemoveFilesFromGroup(int pos, int count);

    // treeview solts
public slots:
    void handleToggleGroupExpansion(const QString &key, const QString &groupKey);
    void handleCloseExpand(const QString &key, const QUrl &parent);
    // 如果不是tree视图，切换到tree视图，就去执行处理dir是否可以展开属性设置
    // 如果是tree视图，切换到普通试图，去掉所有子目录，去掉所有的是否可以展开属性
    void handleSwitchTreeView(const bool isTree);

private:
    bool handleAddChildren(const QString &key,
                           const QList<SortInfoPointer> &children,
                           const QList<FileInfoPointer> &childInfos,
                           const bool isFirstBatch = false);
    void resetFilters(const QDir::Filters filters = QDir::NoFilter);
    void checkNameFilters(const FileItemDataPointer itemData);
    void filterAllFilesOrdered();
    void filterAndSortFiles(const QUrl &dir, const bool fileter = false,
                            const bool reverse = false);
    void resortCurrent(const bool reverse);
    QList<QUrl> filterFilesByParent(const QUrl &dir, const bool byInfo = false);
    void filterTreeDirFiles(const QUrl &parent, const bool byInfo = false);

    bool addChild(const SortInfoPointer &sortInfo,
                  const SortScenarios sort);
    bool sortInfoUpdateByFileInfo(const FileInfoPointer fileInfo);

    void switchTreeView();
    void switchListView();
    QList<QUrl> sortAllTreeFilesByParent(const QUrl &dir, const bool reverse = false);
    QList<QUrl> sortTreeFiles(const QList<QUrl> &children, const bool reverse = false);
    QList<QUrl> removeChildrenByParents(const QList<QUrl> &dirs);
    QList<QUrl> removeVisibleTreeChildren(const QUrl &parent);
    void removeSubDir(const QUrl &dir);
    void removeFileItems(const QList<QUrl> &urls);
    int8_t findDepth(const QUrl &parent);
    int findEndPos(const QUrl &dir);
    int findStartPos(const QUrl &parent);
    int findStartPos(const QList<QUrl> &list, const QUrl &parent);

    void resortVisibleChildren(const QList<QUrl> &fileUrls);
    void insertVisibleChildren(const int startPos, const QList<QUrl> &filterUrls,
                               const InsertOpt opt = InsertOpt::kInsertOptAppend, const int endPos = -1);
    void removeVisibleChildren(const int startPos, const int size);
    void createAndInsertItemData(const int8_t depth, const SortInfoPointer child, const FileInfoPointer info);

    int insertSortList(const QUrl &needNode, const QList<QUrl> &list);
    bool checkFilters(const SortInfoPointer &sortInfo, const bool byInfo = false);
    bool isDefaultHiddenFile(const QUrl &fileUrl);
    QUrl makeParentUrl(const QUrl &url);
    int8_t getDepth(const QUrl &url);
    int findRealShowIndex(const QUrl &preItemUrl);
    int indexOfVisibleChild(const QUrl &itemUrl);
    int setVisibleChildren(const int startPos, const QList<QUrl> &filterUrls,
                           const InsertOpt opt = InsertOpt::kInsertOptAppend, const int endPos = -1);
    bool checkAndUpdateFileInfoUpdate();
    void checkAndSortBytMimeType(const QUrl &url);
    void doCompleteFileInfo(SortInfoPointer sortInfo);

    // 更新排序器上下文
    void updateSorterContext();

    // Grouping-related private methods
    QList<FileItemDataPointer> getAllFiles() const;
    void applyGrouping(const QList<FileItemDataPointer> &files);
    void clearGroupedData();

    // Grouping update handlers
    void handleGroupingInsert();
    void handleGroupingRemove();
    void handleGroupingUpdate();
    void handleGroupingChanged();

    int childrenCountInternal();
    int getChildShowIndexInternal(const QUrl &url);
    void doModelChanged(const ModelChangeType type, int index = 0, int count = 0);

private:
    QUrl current;
    QStringList nameFilters {};
    QDir::Filters filters { QDir::NoFilter };
    QHash<QUrl, QHash<QUrl, SortInfoPointer>> children {};
    mutable QReadWriteLock childrenDataLocker;
    QHash<QUrl, FileItemDataPointer> childrenDataMap {};
    QList<QUrl> visibleChildren {};
    mutable QReadWriteLock locker;
    FileViewFilterCallback filterCallback { nullptr };
    QVariant filterData;
    FileItemDataPointer rootdata { nullptr };
    QString currentKey;
    Global::ItemRoles orgSortRole { Global::ItemRoles::kItemDisplayRole };
    Qt::SortOrder sortOrder { Qt::AscendingOrder };
    DFMIO::DEnumerator::SortRoleCompareFlag sortRole { DFMIO::DEnumerator::SortRoleCompareFlag::kSortRoleCompareDefault };

    // New grouping-related members
    Qt::SortOrder groupOrder { Qt::AscendingOrder };
    std::unique_ptr<GroupingEngine> groupingEngine;
    AbstractGroupStrategy *currentStrategy { nullptr };
    GroupedModelData groupedModelData;
    std::atomic_bool isCurrentGroupingEnabled { false };
    QHash<QString, bool> groupExpansionStates;

    std::atomic_bool isCanceled { false };
    bool isMixDirAndFile { false };
    QHash<QUrl, QList<QUrl>> visibleTreeChildren {};
    QMultiMap<int8_t, QUrl> depthMap;
    std::atomic_bool istree { false };
    std::atomic_bool currentSupportTreeView { false };
    QList<QUrl> fileInfoRefresh;
    QTimer *updateRefresh { nullptr };
    std::atomic_bool mimeSorting { false };
    QSet<QUrl> waitUpdatedFiles;

    // 高性能排序器
    FileViewSorter m_sorter;
};

}

#endif   // FILESORTWORKER_H
