#include "nodetreeview.h"
#include "nodetreemodel.h"
#include <QMenu>
#include <QAction>
#include <QMouseEvent>
#include <QDebug>
#include <QMimeData>
#include <QApplication>
#include <QFile>
#include <QScrollBar>
#include "nodetreeview_p.h"

NodeTreeView::NodeTreeView(QWidget *parent)// 构造函数，初始化 NodeTreeView
    : QTreeView(parent),
      m_isContextMenuOpened{ false },
      m_isEditing{ false },
      m_ignoreThisCurrentLoad{ false },
      m_isLastSelectedFolder{ false }
{
    setHeaderHidden(true);// 隐藏表头

    QFile file(":/styles/nodetreeview.css");
    file.open(QFile::ReadOnly);
    setStyleSheet(file.readAll());// 设置样式表

#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) || defined(Q_OS_WIN) || defined(Q_OS_WINDOWS)
    QFile scollBarStyleFile(QStringLiteral(":/styles/components/custom-scrollbar.css"));
    scollBarStyleFile.open(QFile::ReadOnly);
    QString scrollbarStyleSheet = QString::fromLatin1(scollBarStyleFile.readAll());
    verticalScrollBar()->setStyleSheet(scrollbarStyleSheet);// 设置滚动条样式
#endif

     setRootIsDecorated(false); // 不显示根节点的装饰
    setMouseTracking(true); // 启用鼠标跟踪
    setSelectionMode(QAbstractItemView::MultiSelection); // 设置选择模式为多选
    setContextMenuPolicy(Qt::CustomContextMenu); // 设置上下文菜单策略为自定义
    connect(this, &QWidget::customContextMenuRequested, this,
            &NodeTreeView::onCustomContextMenu); // 连接自定义上下文菜单信号
    contextMenu = new QMenu(this); // 创建上下文菜单
    renameFolderAction = new QAction(tr("Rename Folder"), this);// 创建和连接重命名文件夹动作
    connect(renameFolderAction, &QAction::triggered, this, [this] {
        setIsEditing(true);
        emit renameFolderRequested();
    });
    deleteFolderAction = new QAction(tr("Delete Folder"), this);// 创建和连接删除文件夹动作
    connect(deleteFolderAction, &QAction::triggered, this, &NodeTreeView::onDeleteNodeAction);
    addSubfolderAction = new QAction(tr("Add Subfolder"), this);// 创建和连接添加子文件夹动作
    connect(addSubfolderAction, &QAction::triggered, this, &NodeTreeView::addFolderRequested);

    renameTagAction = new QAction(tr("Rename Tag"), this);// 创建和连接重命名标签动作
    connect(renameTagAction, &QAction::triggered, this, [this] {
        setIsEditing(true);
        emit renameTagRequested();
    });
    changeTagColorAction = new QAction(tr("Change Tag Color"), this); // 创建和连接更改标签颜色动作
    connect(changeTagColorAction, &QAction::triggered, this, &NodeTreeView::onChangeTagColorAction);
    deleteTagAction = new QAction(tr("Delete Tag"), this);// 创建和连接删除标签动作
    connect(deleteTagAction, &QAction::triggered, this, &NodeTreeView::onDeleteNodeAction);
    clearSelectionAction = new QAction(tr("Clear Selection"), this);// 创建和连接清除选择动作
    connect(clearSelectionAction, &QAction::triggered, this, [this] {
        closeCurrentEditor();
        clearSelection();
        setCurrentIndexC(dynamic_cast<NodeTreeModel *>(model())->getAllNotesButtonIndex());
    });

    contextMenuTimer.setInterval(100);// 设置上下文菜单定时器
    contextMenuTimer.setSingleShot(true);
    connect(&contextMenuTimer, &QTimer::timeout, this, [this] {
        if (!m_isEditing) {
            closeCurrentEditor();
        }
    });

    connect(contextMenu, &QMenu::aboutToHide, this, [this] { // 连接上下文菜单隐藏信号
        m_isContextMenuOpened = false;
        // this signal is emitted before QAction::triggered
        contextMenuTimer.start();
    });
    connect(this, &NodeTreeView::expanded, this, &NodeTreeView::onExpanded);// 连接展开和收起信号
    connect(this, &NodeTreeView::collapsed, this, &NodeTreeView::onCollapsed);

     setDragEnabled(true); // 启用拖动
    setAcceptDrops(true); // 启用接受拖放
    setSelectionMode(QAbstractItemView::SingleSelection); // 设置选择模式为单选
}
// 删除节点动作
void NodeTreeView::onDeleteNodeAction()
{
    auto itemType = static_cast<NodeItem::Type>(
            m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
    auto id = m_currentEditingIndex.data(NodeItem::Roles::NodeId).toInt();
    if (itemType == NodeItem::Type::FolderItem || itemType == NodeItem::Type::NoteItem) {
        if (id > SpecialNodeID::DefaultNotesFolder) {
            auto index = m_currentEditingIndex;
            emit deleteNodeRequested(index);
        }
    } else if (itemType == NodeItem::Type::TagItem) {
        auto index = m_currentEditingIndex;
        emit deleteTagRequested(index);
    }
}
// 节点展开时的处理
void NodeTreeView::onExpanded(const QModelIndex &index)
{
    m_expanded.push_back(index.data(NodeItem::Roles::AbsPath).toString());
    emit saveExpand(QStringList::fromVector(m_expanded));
}
// 节点收起时的处理
void NodeTreeView::onCollapsed(const QModelIndex &index)
{
    m_expanded.removeAll(index.data(NodeItem::Roles::AbsPath).toString());
    emit saveExpand(QStringList::fromVector(m_expanded));
}
// 获取当前编辑的索引
const QModelIndex &NodeTreeView::currentEditingIndex() const
{
    return m_currentEditingIndex;
}
// 设置忽略当前加载
void NodeTreeView::setIgnoreThisCurrentLoad(bool newIgnoreThisCurrentLoad)
{
    m_ignoreThisCurrentLoad = newIgnoreThisCurrentLoad;
}
// 文件夹拖放成功时的处理
void NodeTreeView::onFolderDropSuccessful(const QString &path)
{
    auto m_model = dynamic_cast<NodeTreeModel *>(model());
    auto index = m_model->folderIndexFromIdPath(path);
    if (index.isValid()) {
        setCurrentIndexC(index);
    } else {
        setCurrentIndexC(m_model->getAllNotesButtonIndex());
    }
}
// 标签拖放成功时的处理
void NodeTreeView::onTagsDropSuccessful(const QSet<int> &ids)
{
    auto m_model = dynamic_cast<NodeTreeModel *>(model());
    setCurrentIndex(QModelIndex());
    clearSelection();
    setSelectionMode(QAbstractItemView::MultiSelection);
    for (const auto &id : qAsConst(ids)) {
        auto index = m_model->tagIndexFromId(id);
        if (index.isValid()) {
            setCurrentIndex(index);
            setSelectionMode(QAbstractItemView::MultiSelection);
            selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent);
        }
    }

    if (selectionModel()->selectedIndexes().isEmpty()) {
        setCurrentIndexC(m_model->getAllNotesButtonIndex());
    }
}
// 获取主题
Theme::Value NodeTreeView::theme() const
{
    return m_theme;
}

bool NodeTreeView::isDragging() const// 是否正在拖动
{
    return state() == DraggingState;
}

void NodeTreeView::reExpandC()// 重新展开节点
{
    auto needExpand = std::move(m_expanded);
    m_expanded.clear();
    QTreeView::reset();
    for (const auto &path : needExpand) {
        auto m_model = dynamic_cast<NodeTreeModel *>(model());
        auto index = m_model->folderIndexFromIdPath(path);
        if (index.isValid()) {
            expand(index);
        }
    }
}

void NodeTreeView::reExpandC(const QStringList &expanded)// 重新展开节点（带参数）
{
    m_expanded.clear();
    m_expanded = expanded.toVector();
    reExpandC();
}

void NodeTreeView::onChangeTagColorAction()// 更改标签颜色动作
{
    auto itemType = static_cast<NodeItem::Type>(
            m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
    if (itemType == NodeItem::Type::TagItem) {
        auto index = m_currentEditingIndex;
        emit changeTagColorRequested(index);
    }
}

void NodeTreeView::onRequestExpand(const QString &folderPath)// 请求展开节点
{
    auto m_model = dynamic_cast<NodeTreeModel *>(model());
    expand(m_model->folderIndexFromIdPath(folderPath));
}

void NodeTreeView::onUpdateAbsPath(const QString &oldPath, const QString &newPath)// 更新绝对路径
{
    std::transform(m_expanded.begin(), m_expanded.end(), m_expanded.begin(), [&](QString s) {
        s.replace(s.indexOf(oldPath), oldPath.size(), newPath);
        return s;
    });
}

void NodeTreeView::updateEditingIndex(QPoint pos)// 更新编辑索引
{
    auto index = indexAt(pos);
    if (indexAt(pos) != m_currentEditingIndex && !m_isContextMenuOpened && !m_isEditing) {
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        if (itemType == NodeItem::Type::FolderItem || itemType == NodeItem::Type::TagItem
            || itemType == NodeItem::Type::TrashButton
            || itemType == NodeItem::Type::AllNoteButton) {
            closePersistentEditor(m_currentEditingIndex);
            openPersistentEditor(index);
            m_currentEditingIndex = index;
        } else {
            closeCurrentEditor();
        }
    }
}

void NodeTreeView::closeCurrentEditor()// 关闭当前编辑器
{
    closePersistentEditor(m_currentEditingIndex);
    m_currentEditingIndex = QModelIndex();
}

void NodeTreeView::selectionChanged(const QItemSelection &selected,// 选择发生变化时的处理
                                    const QItemSelection &deselected)
{
    QTreeView::selectionChanged(selected, deselected);
    if (m_ignoreThisCurrentLoad) {
        return;
    }
    auto indexes = selectedIndexes();
    QSet<int> tagIds;
    for (const auto index : qAsConst(indexes)) {
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        switch (itemType) {
        case NodeItem::Type::RootItem:
        case NodeItem::Type::FolderSeparator:
        case NodeItem::Type::TagSeparator:
        case NodeItem::Type::NoteItem: {
            return;
        }
        case NodeItem::Type::AllNoteButton: {
            auto folderPath = index.data(NodeItem::Roles::AbsPath).toString();
            m_lastSelectFolder = folderPath;
            m_isLastSelectedFolder = true;
            emit loadNotesInFolderRequested(SpecialNodeID::RootFolder, true);
            emit saveSelected(true, NodePath::getAllNoteFolderPath(), {});
            return;
        }
        case NodeItem::Type::TrashButton: {
            auto folderPath = index.data(NodeItem::Roles::AbsPath).toString();
            m_lastSelectFolder = folderPath;
            m_isLastSelectedFolder = true;
            emit loadNotesInFolderRequested(SpecialNodeID::TrashFolder, true);
            emit saveSelected(true, NodePath::getTrashFolderPath(), {});
            return;
        }
        case NodeItem::Type::FolderItem: {
            auto folderId = index.data(NodeItem::Roles::NodeId).toInt();
            auto folderPath = index.data(NodeItem::Roles::AbsPath).toString();
            m_lastSelectFolder = folderPath;
            m_isLastSelectedFolder = true;
            emit saveSelected(true, folderPath, {});
            emit loadNotesInFolderRequested(folderId, false);
            return;
        }
        case NodeItem::Type::TagItem: {
            auto tagId = index.data(NodeItem::Roles::NodeId).toInt();
            tagIds.insert(tagId);
        }
        }
    }
    if (!tagIds.isEmpty()) {
        if (m_isLastSelectedFolder) {
            emit saveLastSelectedNote();
        }
        m_isLastSelectedFolder = false;
        emit saveSelected(false, {}, tagIds);
        emit loadNotesInTagsRequested(tagIds);
    }
}

void NodeTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)// 当前索引发生变化时的处理
{
    QTreeView::currentChanged(current, previous);
    auto itemType = static_cast<NodeItem::Type>(current.data(NodeItem::Roles::ItemType).toInt());
    if (itemType == NodeItem::Type::TagItem) {
        setSelectionMode(QAbstractItemView::MultiSelection);
    } else {
        clearSelection();
        setSelectionMode(QAbstractItemView::SingleSelection);
        selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current);
    }
}

void NodeTreeView::dragEnterEvent(QDragEnterEvent *event)// 拖动进入事件
{
    if (event->mimeData()->hasFormat(NOTE_MIME)) {
        event->acceptProposedAction();
    } else {
        QTreeView::dragEnterEvent(event);
    }
}

void NodeTreeView::dragMoveEvent(QDragMoveEvent *event)// 拖动移动事件
{
    if (event->mimeData()->hasFormat(NOTE_MIME)) {
        auto index = indexAt(event->pos());
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        if (itemType != NodeItem::Type::AllNoteButton) {
            updateEditingIndex(event->pos());
            event->acceptProposedAction();
        }
    } else {
        if (event->mimeData()->hasFormat(TAG_MIME)) {
            if (event->pos().y() < visualRect(m_treeSeparator[1]).y() + 25) {
                event->ignore();
                return;
            }
        } else if (event->mimeData()->hasFormat(FOLDER_MIME)) {
            auto trashRect =
                    visualRect(dynamic_cast<NodeTreeModel *>(model())->getTrashButtonIndex());
            if (event->pos().y() > (trashRect.y() + 5)
                && event->pos().y() < (trashRect.bottom() - 5)) {
                setDropIndicatorShown(true);
                QTreeView::dragMoveEvent(event);
                return;
            }
            if (event->pos().y() > visualRect(m_treeSeparator[1]).y()) {
                event->ignore();
                return;
            }
            if (event->pos().y() < visualRect(m_defaultNotesIndex).y() + 25) {
                event->ignore();
                return;
            }
        }
        setDropIndicatorShown(true);
        QTreeView::dragMoveEvent(event);
    }
}

void NodeTreeView::reset()// 重置视图
{
    closeCurrentEditor();
    reExpandC();
}

void NodeTreeView::dropEvent(QDropEvent *event)// 拖放事件
{
    if (event->mimeData()->hasFormat(NOTE_MIME)) {
        auto dropIndex = indexAt(event->pos());
        if (dropIndex.isValid()) {
            auto itemType =
                    static_cast<NodeItem::Type>(dropIndex.data(NodeItem::Roles::ItemType).toInt());
            bool ok = false;
            auto idl = QString::fromUtf8(event->mimeData()->data(NOTE_MIME))
                               .split(QStringLiteral(PATH_SEPARATOR));
            for (const auto &s : qAsConst(idl)) {
                auto nodeId = s.toInt(&ok);
                if (ok) {
                    if (itemType == NodeItem::Type::FolderItem) {
                        emit moveNodeRequested(nodeId, dropIndex.data(NodeItem::NodeId).toInt());
                        event->acceptProposedAction();
                    } else if (itemType == NodeItem::Type::TagItem) {
                        emit addNoteToTag(nodeId, dropIndex.data(NodeItem::NodeId).toInt());
                    } else if (itemType == NodeItem::Type::TrashButton) {
                        emit moveNodeRequested(nodeId, SpecialNodeID::TrashFolder);
                        event->acceptProposedAction();
                    }
                }
            }
        }
    } else {
        QTreeView::dropEvent(event);
    }
}

void NodeTreeView::setIsEditing(bool newIsEditing)// 设置是否正在编辑
{
    m_isEditing = newIsEditing;
}

void NodeTreeView::onRenameFolderFinished(const QString &newName)// 重命名文件夹完成
{
    if (m_currentEditingIndex.isValid()) {
        auto itemType = static_cast<NodeItem::Type>(
                m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
        if (itemType == NodeItem::Type::FolderItem) {
            QModelIndex index = m_currentEditingIndex;
            closeCurrentEditor();
            emit renameFolderInDatabase(index, newName);
        } else {
            qDebug() << __FUNCTION__ << "wrong type";
        }
    } /*else {
        qDebug() << __FUNCTION__ << "m_currentEditingIndex is not valid";
    }*/
}

void NodeTreeView::onRenameTagFinished(const QString &newName)// 重命名标签完成
{
    if (m_currentEditingIndex.isValid()) {
        auto itemType = static_cast<NodeItem::Type>(
                m_currentEditingIndex.data(NodeItem::Roles::ItemType).toInt());
        if (itemType == NodeItem::Type::TagItem) {
            QModelIndex index = m_currentEditingIndex;
            closeCurrentEditor();
            emit renameTagInDatabase(index, newName);
        } else {
            qDebug() << __FUNCTION__ << "wrong type";
        }
    } /*else {
        qDebug() << __FUNCTION__ << "m_currentEditingIndex is not valid";
    }*/
}

void NodeTreeView::setCurrentIndexC(const QModelIndex &index)// 设置当前索引
{
    setCurrentIndex(index);
    clearSelection();
    setSelectionMode(QAbstractItemView::SingleSelection);
    selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent);
}

void NodeTreeView::setCurrentIndexNC(const QModelIndex &index)// 设置当前索引（不改变选择模式）
{
    setCurrentIndex(index);
}

void NodeTreeView::setTheme(Theme::Value theme)// 设置主题
{
    setCSSThemeAndUpdate(this, theme);
    m_theme = theme;
}

void NodeTreeView::onCustomContextMenu(QPoint point)// 自定义上下文菜单请求
{
    QModelIndex index = indexAt(point);
    if (index.isValid()) {
        auto itemType = static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
        contextMenu->clear();
        if (itemType == NodeItem::Type::FolderItem) {
            auto id = index.data(NodeItem::Roles::NodeId).toInt();
            if (id != SpecialNodeID::DefaultNotesFolder) {
                m_isContextMenuOpened = true;
                contextMenu->addAction(renameFolderAction);
                contextMenu->addAction(deleteFolderAction);
                contextMenu->addSeparator();
                contextMenu->addAction(addSubfolderAction);
                contextMenu->exec(viewport()->mapToGlobal(point));
            }
        } else if (itemType == NodeItem::Type::TagItem) {
            m_isContextMenuOpened = true;
            contextMenu->addAction(renameTagAction);
            contextMenu->addAction(changeTagColorAction);
            contextMenu->addAction(clearSelectionAction);
            contextMenu->addSeparator();
            contextMenu->addAction(deleteTagAction);
            contextMenu->exec(viewport()->mapToGlobal(point));
        }
    }
}

void NodeTreeView::setTreeSeparator(const QVector<QModelIndex> &newTreeSeparator,// 设置树分隔符
                                    const QModelIndex &defaultNotesIndex)
{
    for (const auto &sep : qAsConst(m_treeSeparator)) {
        closePersistentEditor(sep);
    }
    m_treeSeparator = newTreeSeparator;
    for (const auto &sep : qAsConst(m_treeSeparator)) {
        openPersistentEditor(sep);
    }
    m_defaultNotesIndex = defaultNotesIndex;
}

void NodeTreeView::mouseMoveEvent(QMouseEvent *event)// 鼠标移动事件
{
    Q_D(NodeTreeView);
    QPoint topLeft;
    QPoint bottomRight = event->pos();
    if (state() == ExpandingState || state() == CollapsingState) {
        return;
    }

    updateEditingIndex(event->pos());
    if (state() == DraggingState) {
        topLeft = d->pressedPosition - d->offset();
        if ((topLeft - bottomRight).manhattanLength() > QApplication::startDragDistance()) {
            d->pressedIndex = QModelIndex();
            startDrag(d->model->supportedDragActions());
            setState(NoState); // the startDrag will return when the dnd operation is done
            stopAutoScroll();
        }
        return;
    }
    if (d->pressedIndex.isValid() && (state() != DragSelectingState)
        && (event->buttons() != Qt::NoButton)) {
        setState(DraggingState);
        return;
    }
}

void NodeTreeView::mousePressEvent(QMouseEvent *event)// 鼠标按下事件
{
    Q_D(NodeTreeView);
    d->delayedAutoScroll.stop();
    {
        auto index = indexAt(event->pos());
        if (index.isValid()) {
            auto itemType =
                    static_cast<NodeItem::Type>(index.data(NodeItem::Roles::ItemType).toInt());
            switch (itemType) {
            case NodeItem::Type::FolderItem: {
                auto rect = visualRect(index);
                auto iconRect = QRect(rect.x() + 5, rect.y() + (rect.height() - 20) / 2, 20, 20);
                if (iconRect.contains(event->pos())) {
                    if (isExpanded(index)) {
                        collapse(index);
                    } else {
                        expand(index);
                    }
                    return;
                }
                setCurrentIndexC(index);
                break;
            }
            case NodeItem::Type::TagItem: {
                auto oldIndexes = selectionModel()->selectedIndexes();
                for (const auto &ix : qAsConst(oldIndexes)) {
                    auto selectedItemType =
                            static_cast<NodeItem::Type>(ix.data(NodeItem::Roles::ItemType).toInt());
                    if (selectedItemType != NodeItem::Type::TagItem) {
                        setCurrentIndex(QModelIndex());
                        clearSelection();
                        break;
                    }
                }

                if (selectionModel()->isSelected(index)) {
                    m_needReleaseIndex = index;
                } else {
                    setCurrentIndex(index);
                    setSelectionMode(QAbstractItemView::MultiSelection);
                    selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent);
                }
                break;
            }
            case NodeItem::Type::AllNoteButton:
            case NodeItem::Type::TrashButton: {
                setCurrentIndexC(index);
                break;
            }
            default: {
                break;
            }
            }
        }
    }
    QPoint pos = event->pos();
    QPersistentModelIndex index = indexAt(pos);
    d->pressedAlreadySelected = d->selectionModel->isSelected(index);
    d->pressedIndex = index;
    d->pressedModifiers = event->modifiers();
    QPoint offset = d->offset();
    d->pressedPosition = pos + offset;
    updateEditingIndex(event->pos());
}

void NodeTreeView::leaveEvent(QEvent *event)// 离开事件
{
    if (!m_isContextMenuOpened && !m_isEditing) {
        closeCurrentEditor();
        QTreeView::leaveEvent(event);
    }
}

void NodeTreeView::mouseReleaseEvent(QMouseEvent *event)// 鼠标释放
{
    Q_UNUSED(event);
    Q_D(NodeTreeView);
    if (m_needReleaseIndex.isValid()) {
        selectionModel()->select(m_needReleaseIndex, QItemSelectionModel::Deselect);
        if (selectionModel()->selectedIndexes().isEmpty()) {
            if (!m_isLastSelectedFolder) {
                auto index = dynamic_cast<NodeTreeModel *>(model())->folderIndexFromIdPath(
                        m_lastSelectFolder);
                if (index.isValid()) {
                    emit requestLoadLastSelectedNote();
                    setCurrentIndexC(index);
                } else {
                    setCurrentIndexC(
                            dynamic_cast<NodeTreeModel *>(model())->getAllNotesButtonIndex());
                }
            } else {
                setCurrentIndexC(dynamic_cast<NodeTreeModel *>(model())->getAllNotesButtonIndex());
            }
        }
    }
    m_needReleaseIndex = QModelIndex();
    setState(NoState);
    d->pressedIndex = QPersistentModelIndex();
}

void NodeTreeView::mouseDoubleClickEvent(QMouseEvent *event)// 鼠标双击
{
    Q_UNUSED(event);
    Q_D(NodeTreeView);
    d->pressedIndex = QModelIndex();
    m_needReleaseIndex = QModelIndex();
    //    QTreeView::mouseDoubleClickEvent(event);
}
