#include "ElaNavigationStyle.h"

#include <QPainter>
#include <QPainterPath>
#include <QPropertyAnimation>
#include <QStyleOption>

#include "ElaNavigationModel.h"
#include "ElaNavigationNode.h"
#include "ElaNavigationView.h"
#include "ElaTheme.h"
ElaNavigationStyle::ElaNavigationStyle(QStyle *style) {
    _pOpacity              = 1;
    _pItemHeight           = 40;
    _pLastSelectMarkTop    = 10.0;
    _pLastSelectMarkBottom = 10.0;
    _pSelectMarkTop        = 10.0;
    _pSelectMarkBottom     = 10.0;

    // Mark向上
    _lastSelectMarkTopAnimation = new QPropertyAnimation(this, "pLastSelectMarkTop");
    connect(_lastSelectMarkTopAnimation, &QPropertyAnimation::valueChanged, this,
            [=](const QVariant &value) { _pNavigationView->viewport()->update(); });
    _lastSelectMarkTopAnimation->setDuration(300);
    _lastSelectMarkTopAnimation->setEasingCurve(QEasingCurve::InOutSine);

    _selectMarkBottomAnimation = new QPropertyAnimation(this, "pSelectMarkBottom");
    connect(_selectMarkBottomAnimation, &QPropertyAnimation::valueChanged, this,
            [=](const QVariant &value) { _pNavigationView->viewport()->update(); });
    _selectMarkBottomAnimation->setDuration(300);
    _selectMarkBottomAnimation->setEasingCurve(QEasingCurve::InOutSine);
    connect(_lastSelectMarkTopAnimation, &QPropertyAnimation::finished, this, [=]() {
        _isSelectMarkDisplay = true;
        _lastSelectedNode    = nullptr;
        _selectMarkBottomAnimation->setStartValue(0);
        _selectMarkBottomAnimation->setEndValue(10);
        _selectMarkBottomAnimation->start();
    });

    // Mark向下
    _lastSelectMarkBottomAnimation = new QPropertyAnimation(this, "pLastSelectMarkBottom");
    connect(_lastSelectMarkBottomAnimation, &QPropertyAnimation::valueChanged, this,
            [=](const QVariant &value) { _pNavigationView->viewport()->update(); });
    _lastSelectMarkBottomAnimation->setDuration(300);
    _lastSelectMarkBottomAnimation->setEasingCurve(QEasingCurve::InOutSine);

    _selectMarkTopAnimation = new QPropertyAnimation(this, "pSelectMarkTop");
    connect(_selectMarkTopAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant &value) { _pNavigationView->viewport()->update(); });
    _selectMarkTopAnimation->setDuration(300);
    _selectMarkTopAnimation->setEasingCurve(QEasingCurve::InOutSine);
    connect(_lastSelectMarkBottomAnimation, &QPropertyAnimation::finished, this, [=]() {
        _isSelectMarkDisplay = true;
        _lastSelectedNode    = nullptr;
        _selectMarkTopAnimation->setStartValue(0);
        _selectMarkTopAnimation->setEndValue(10);
        _selectMarkTopAnimation->start();
    });
    _themeMode = eTheme->getThemeMode();
    connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}

ElaNavigationStyle::~ElaNavigationStyle() {}

void ElaNavigationStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const {
    switch (element) {
    case QStyle::PE_PanelItemViewItem: {
        // Item背景
        if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
            painter->save();
            QModelIndex        index = vopt->index;
            ElaNavigationNode *node  = static_cast<ElaNavigationNode *>(index.internalPointer());
            if (this->_opacityAnimationTargetNode && node->getParentNode() == this->_opacityAnimationTargetNode) {
                painter->setOpacity(_pOpacity);
            }
            painter->setRenderHint(QPainter::Antialiasing);
            QRect itemRect = vopt->rect;
            itemRect.setTop(itemRect.top() + 2);
            itemRect.setBottom(itemRect.bottom() - 2);
            QPainterPath path;
            path.addRoundedRect(itemRect, 8, 8);
            if (vopt->state & QStyle::State_Selected) {
                if (index == _pPressIndex) {
                    // 选中时点击
                    painter->fillPath(path, ElaThemeColor(_themeMode, BasicHoverAlpha));
                } else {
                    if (vopt->state & QStyle::State_MouseOver) {
                        // 选中时覆盖
                        painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedHoverAlpha));
                    } else {
                        // 选中
                        painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedAlpha));
                    }
                }
            } else {
                if (index == _pPressIndex) {
                    // 点击时颜色
                    painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedHoverAlpha));
                } else {
                    if (vopt->state & QStyle::State_MouseOver) {
                        // 覆盖时颜色
                        painter->fillPath(path, ElaThemeColor(_themeMode, BasicHoverAlpha));
                    }
                }
            }
            painter->restore();
        }
        return;
    }
    case QStyle::PE_PanelItemViewRow: {
        // 行背景
        return;
    }
    case QStyle::PE_IndicatorBranch: {
        // Branch指示器
        return;
    }
    default: {
        break;
    }
    }
    QProxyStyle::drawPrimitive(element, option, painter, widget);
}

void ElaNavigationStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const {
    switch (element) {
    case QStyle::CE_ShapedFrame: {
        // viewport视口外的其他区域背景
        return;
    }
    case QStyle::CE_ItemViewItem: {
        if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
            // 背景绘制
            this->drawPrimitive(QStyle::PE_PanelItemViewItem, option, painter, widget);

            // 内容绘制
            QRect itemRect = option->rect;
            painter->save();
            painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
            ElaNavigationNode  *node  = static_cast<ElaNavigationNode *>(vopt->index.internalPointer());
            ElaNavigationModel *model = dynamic_cast<ElaNavigationModel *>(const_cast<QAbstractItemModel *>(vopt->index.model()));

            if (this->_opacityAnimationTargetNode && node->getParentNode() == this->_opacityAnimationTargetNode) {
                painter->setOpacity(_pOpacity);
            }

            // 选中特效
            if (_isSelectMarkDisplay && (node == model->getSelectedNode() || node == model->getSelectedExpandedNode())) {
                painter->setPen(Qt::NoPen);
                painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
                painter->drawRoundedRect(
                    QRectF(itemRect.x() + 3, itemRect.y() + _pSelectMarkTop, 3, itemRect.height() - _pSelectMarkTop - _pSelectMarkBottom), 3, 3);
            }
            if (node == _lastSelectedNode) {
                painter->setPen(Qt::NoPen);
                painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
                painter->drawRoundedRect(
                    QRectF(itemRect.x() + 3, itemRect.y() + _pLastSelectMarkTop, 3, itemRect.height() - _pLastSelectMarkTop - _pLastSelectMarkBottom),
                    3, 3);
            }

            // 图标绘制
            painter->setPen(vopt->index == _pPressIndex ? ElaThemeColor(_themeMode, BasicTextPress) : ElaThemeColor(_themeMode, BasicText));
            if (node->getAwesome() != ElaIconType::None) {
                painter->save();
                QFont iconFont = QFont("ElaAwesome");
                iconFont.setPixelSize(17);
                painter->setFont(iconFont);
                painter->drawText(QRect(itemRect.x(), itemRect.y(), _iconAreaWidth, itemRect.height()), Qt::AlignCenter,
                                  QChar((unsigned short)node->getAwesome()));
                painter->restore();
            }

            int viewWidth = widget->width();
            // 文字绘制
            painter->setPen(vopt->index == _pPressIndex ? ElaThemeColor(_themeMode, BasicTextPress) : ElaThemeColor(_themeMode, BasicText));
            QRect textRect;
            if (node->getAwesome() != ElaIconType::None) {
                textRect = QRect(itemRect.x() + _iconAreaWidth, itemRect.y(),
                                 itemRect.width() - _textRightSpacing - _indicatorIconAreaWidth - _iconAreaWidth, itemRect.height());
            } else {
                textRect = QRect(itemRect.x() + _leftPadding, itemRect.y(),
                                 itemRect.width() - _textRightSpacing - _indicatorIconAreaWidth - _leftPadding, itemRect.height());
            }
            QString text = painter->fontMetrics().elidedText(node->getNodeTitle(), Qt::ElideRight, textRect.width());
            painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);

            if (viewWidth > _pNavigationView->getNavigationBarPrivate()->_pNavigationBarWidth - _indicatorIconAreaWidth) {
                // 展开图标 KeyPoints
                if (node->getIsExpanderNode()) {
                    if (node->getIsHasChild()) {
                        QRectF expandIconRect(itemRect.right() - _indicatorIconAreaWidth, itemRect.y(), 17, itemRect.height());

                        painter->save();
                        QFont iconFont = QFont("ElaAwesome");
                        iconFont.setPixelSize(17);
                        painter->setFont(iconFont);
                        painter->translate(expandIconRect.x() + (qreal)expandIconRect.width() / 2,
                                           expandIconRect.y() + (qreal)expandIconRect.height() / 2);
                        if (node == _expandAnimationTargetNode) {
                            painter->rotate(_pRotate);
                        } else {
                            if (node->getIsExpanded()) {
                                // 展开
                                painter->rotate(-180);
                            } else {
                                // 未展开
                                painter->rotate(0);
                            }
                        }
                        painter->translate(-expandIconRect.x() - (qreal)expandIconRect.width() / 2 + 1,
                                           -expandIconRect.y() - (qreal)expandIconRect.height() / 2);
                        painter->drawText(expandIconRect, Qt::AlignVCenter, QChar((unsigned short)ElaIconType::AngleDown));
                        painter->restore();
                    }
                    if (node->getIsChildHasKeyPoints()) {
                        painter->save();
                        painter->setPen(Qt::NoPen);
                        painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
                        painter->drawEllipse(QPoint(itemRect.right() - 17, itemRect.y() + 12), 3, 3);
                        painter->restore();
                    }
                } else {
                    int keyPoints = node->getKeyPoints();
                    if (keyPoints) {
                        // KeyPoints
                        painter->save();
                        painter->setPen(Qt::NoPen);
                        painter->setBrush(Qt::white);
                        painter->drawEllipse(QPoint(itemRect.right() - 26, itemRect.y() + itemRect.height() / 2), 10, 10);
                        painter->setBrush(ElaThemeColor(_themeMode, StatusDanger));
                        painter->drawEllipse(QPoint(itemRect.right() - 26, itemRect.y() + itemRect.height() / 2), 9, 9);
                        painter->setPen(QPen(Qt::white, 2));
                        QFont font = painter->font();
                        font.setBold(true);
                        if (keyPoints > 99) {
                            keyPoints = 99;
                        }
                        if (keyPoints > 9) {
                            font.setPixelSize(11);
                        } else {
                            font.setPixelSize(12);
                        }
                        painter->setFont(font);
                        painter->drawText(keyPoints > 9 ? itemRect.right() - 33 : itemRect.right() - 30, itemRect.y() + itemRect.height() / 2 + 4,
                                          QString::number(keyPoints));
                        painter->restore();
                    }
                }
            }
            painter->restore();
        }

        return;
    }
    default: {
        break;
    }
    }
    QProxyStyle::drawControl(element, option, painter, widget);
}

QSize ElaNavigationStyle::sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const {
    switch (type) {
    case QStyle::CT_ItemViewItem: {
        QSize itemSize = QProxyStyle::sizeFromContents(type, option, size, widget);
        itemSize.setHeight(_pItemHeight);
        return itemSize;
    }
    default: {
        break;
    }
    }
    return QProxyStyle::sizeFromContents(type, option, size, widget);
}

void ElaNavigationStyle::navigationNodeStateChange(QVariantMap data) {
    if (data.contains("Expand")) {
        ElaNavigationNode *lastExpandNode        = _expandAnimationTargetNode;
        _opacityAnimationTargetNode              = data.value("Expand").value<ElaNavigationNode *>();
        _expandAnimationTargetNode               = _opacityAnimationTargetNode;
        QPropertyAnimation *nodeOpacityAnimation = new QPropertyAnimation(this, "pOpacity");
        connect(nodeOpacityAnimation, &QPropertyAnimation::finished, this, [=]() { _opacityAnimationTargetNode = nullptr; });
        connect(nodeOpacityAnimation, &QPropertyAnimation::valueChanged, this,
                [=](const QVariant &value) { _pNavigationView->viewport()->update(); });
        nodeOpacityAnimation->setDuration(600);
        nodeOpacityAnimation->setEasingCurve(QEasingCurve::InOutSine);
        nodeOpacityAnimation->setKeyValueAt(0.4, 0);
        nodeOpacityAnimation->setStartValue(0);
        nodeOpacityAnimation->setEndValue(1);
        nodeOpacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);

        QPropertyAnimation *rotateAnimation = new QPropertyAnimation(this, "pRotate");
        connect(rotateAnimation, &QPropertyAnimation::finished, this, [=]() { _expandAnimationTargetNode = nullptr; });
        connect(rotateAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant &value) { _pNavigationView->viewport()->update(); });
        rotateAnimation->setDuration(300);
        rotateAnimation->setEasingCurve(QEasingCurve::InOutSine);
        if (lastExpandNode == _expandAnimationTargetNode) {
            rotateAnimation->setStartValue(_pRotate);
        } else {
            rotateAnimation->setStartValue(0);
        }
        rotateAnimation->setEndValue(-180);
        rotateAnimation->start(QAbstractAnimation::DeleteWhenStopped);
    } else if (data.contains("Collapse")) {
        ElaNavigationNode *lastExpandNode = _expandAnimationTargetNode;
        _opacityAnimationTargetNode       = data.value("Collapse").value<ElaNavigationNode *>();
        _expandAnimationTargetNode        = _opacityAnimationTargetNode;
        _pOpacity                         = 0;

        QPropertyAnimation *rotateAnimation = new QPropertyAnimation(this, "pRotate");
        connect(rotateAnimation, &QPropertyAnimation::finished, this, [=]() {
            _pOpacity                  = 1;
            _expandAnimationTargetNode = nullptr;
        });
        connect(rotateAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant &value) { _pNavigationView->viewport()->update(); });
        rotateAnimation->setDuration(300);
        rotateAnimation->setEasingCurve(QEasingCurve::InOutSine);
        if (lastExpandNode == _expandAnimationTargetNode) {
            rotateAnimation->setStartValue(_pRotate);
        } else {
            rotateAnimation->setStartValue(-180);
        }
        rotateAnimation->setEndValue(0);
        rotateAnimation->start(QAbstractAnimation::DeleteWhenStopped);
    } else if (data.contains("SelectMarkChanged")) {
        _lastSelectedNode               = data.value("LastSelectedNode").value<ElaNavigationNode *>();
        ElaNavigationNode *selectedNode = data.value("SelectedNode").value<ElaNavigationNode *>();
        bool               direction    = _compareItemY(selectedNode, _lastSelectedNode);
        _pLastSelectMarkTop             = 10;
        _pLastSelectMarkBottom          = 10;
        _pSelectMarkTop                 = 10;
        _pSelectMarkBottom              = 10;
        if (direction) {
            _lastSelectMarkTopAnimation->setStartValue(10);
            _lastSelectMarkTopAnimation->setEndValue(0);
            _lastSelectMarkTopAnimation->start();
            _lastSelectMarkBottomAnimation->stop();
            _selectMarkTopAnimation->stop();
            _isSelectMarkDisplay = false;
        } else {
            _lastSelectMarkBottomAnimation->setStartValue(10);
            _lastSelectMarkBottomAnimation->setEndValue(0);
            _lastSelectMarkBottomAnimation->start();
            _lastSelectMarkTopAnimation->stop();
            _selectMarkBottomAnimation->stop();
            _isSelectMarkDisplay = false;
        }
    }
}

bool ElaNavigationStyle::_compareItemY(ElaNavigationNode *node1, ElaNavigationNode *node2) {
    // 返回true 即node1 高于 node2
    if (!node1) {
        return false;
    }
    if (!node2) {
        return true;
    }
    // 同一父节点
    if (node1->getParentNode() == node2->getParentNode()) {
        if (node1->getModelIndex().row() < node2->getModelIndex().row()) {
            return true;
        } else {
            return false;
        }
    } else {
        ElaNavigationNode *node1OriginalNode = node1->getOriginalNode();
        ElaNavigationNode *node2OriginalNode = node2->getOriginalNode();
        // 不同父节点  相同起源节点
        if (node1OriginalNode == node2OriginalNode) {
            int node1Depth = node1->getDepth();
            int node2Depth = node2->getDepth();
            // 相同深度
            if (node1Depth == node2Depth) {
                ElaNavigationNode *node1ParentNode = node1->getParentNode();
                ElaNavigationNode *node2ParentNode = node2->getParentNode();
                if (node1ParentNode->getModelIndex().row() < node2ParentNode->getModelIndex().row()) {
                    return true;
                } else {
                    return false;
                }
            } else {
                if (node1Depth < node2Depth) {
                    ElaNavigationNode *node2ParentNode = node2->getParentNode();
                    while (node2ParentNode->getDepth() != node1Depth) {
                        node2ParentNode = node2ParentNode->getParentNode();
                    }
                    // 父子节点关系
                    if (node1 == node2ParentNode) {
                        return true;
                    }
                    if (node1->getModelIndex().row() < node2ParentNode->getModelIndex().row()) {
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    ElaNavigationNode *node1ParentNode = node1->getParentNode();
                    while (node1ParentNode->getDepth() != node2Depth) {
                        node1ParentNode = node1ParentNode->getParentNode();
                    }
                    if (node2 == node1ParentNode) {
                        return false;
                    }
                    if (node1ParentNode->getModelIndex().row() < node2->getModelIndex().row()) {
                        return true;
                    } else {
                        return false;
                    }
                }
            }
        } else {
            if (node1OriginalNode->getModelIndex().row() < node2OriginalNode->getModelIndex().row()) {
                return true;
            } else {
                return false;
            }
        }
    }
}
