#include "ElaRoller.h"
#include "ElaRollerPrivate.h"
#include "ElaTheme.h"
#include <QPainter>
#include <QPropertyAnimation>
#include <QWheelEvent>
#include <cmath>

Q_PROPERTY_CREATE_Q_CPP(ElaRoller, int, BorderRadius)
ElaRoller::ElaRoller(QWidget *parent) : QWidget{parent}, d_ptr(new ElaRollerPrivate()) {
    Q_D(ElaRoller);
    d->q_ptr             = this;
    d->_pScrollOffset    = 0;
    d->_pItemHeight      = 35;
    d->_pBorderRadius    = 3;
    d->_pMaxVisibleItems = 5;
    d->_pCurrentIndex    = 0;
    setFixedSize(90, 175);
    setMouseTracking(true);
    setObjectName("ElaRoller");
    setStyleSheet("#ElaRoller{background-color:transparent;}");
    QFont font = this->font();
    font.setPixelSize(16);
    setFont(font);

    d->_scrollAnimation = new QPropertyAnimation(d, "pScrollOffset");
    connect(d->_scrollAnimation, &QPropertyAnimation::valueChanged, this, [=]() { update(); });
    connect(d->_scrollAnimation, &QPropertyAnimation::finished, this, [=]() {
        while (d->_pScrollOffset < -d->_pItemList.size() * d->_pItemHeight) {
            d->_pScrollOffset += d->_pItemList.size() * d->_pItemHeight;
        }
        while (d->_pScrollOffset > d->_pItemList.size() * d->_pItemHeight) {
            d->_pScrollOffset -= d->_pItemList.size() * d->_pItemHeight;
        }
        d->_targetScrollOffset = d->_pScrollOffset;
        int currentIndex       = 0;
        if (d->_pScrollOffset >= 0) {
            currentIndex = d->_pScrollOffset / d->_pItemHeight;
        } else if (d->_pScrollOffset <= -d->_pItemHeight) {
            currentIndex = d->_pItemList.count() + d->_pScrollOffset / d->_pItemHeight;
        }
        if (currentIndex != d->_pCurrentIndex) {
            d->_pCurrentIndex = currentIndex;
            Q_EMIT pCurrentIndexChanged();
        }
        update();
    });

    d->_scrollAnimation->setDuration(300);
    d->_scrollAnimation->setEasingCurve(QEasingCurve::OutCubic);

    d->_themeMode = eTheme->getThemeMode();
    connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { d->_themeMode = themeMode; });
}

ElaRoller::~ElaRoller() {}

QString ElaRoller::getCurrentData() const {
    Q_D(const ElaRoller);
    return d->_pItemList[d->_pCurrentIndex];
}

void ElaRoller::setItemList(QStringList itemList) {
    Q_D(ElaRoller);
    d->_pItemList = std::move(itemList);
    update();
    Q_EMIT pItemListChanged();
}

QStringList ElaRoller::getItemList() const {
    Q_D(const ElaRoller);
    return d->_pItemList;
}

void ElaRoller::setItemHeight(int itemHeight) {
    Q_D(ElaRoller);
    d->_pItemHeight = itemHeight;
    setFixedHeight(d->_pMaxVisibleItems * d->_pItemHeight);
    update();
    Q_EMIT pItemHeightChanged();
}

int ElaRoller::getItemHeight() const {
    Q_D(const ElaRoller);
    return d->_pItemHeight;
}

void ElaRoller::setMaxVisibleItems(int maxVisibleItems) {
    Q_D(ElaRoller);
    d->_pMaxVisibleItems = maxVisibleItems;
    setFixedHeight(d->_pMaxVisibleItems * d->_pItemHeight);
    update();
    Q_EMIT pMaxVisibleItemsChanged();
}

int ElaRoller::getMaxVisibleItems() const {
    Q_D(const ElaRoller);
    return d->_pMaxVisibleItems;
}

void ElaRoller::setCurrentIndex(int currentIndex) {
    Q_D(ElaRoller);
    if (currentIndex >= d->_pItemList.count()) {
        return;
    }
    d->_pCurrentIndex      = currentIndex;
    d->_pScrollOffset      = d->_pItemHeight * currentIndex;
    d->_targetScrollOffset = d->_pScrollOffset;
    update();
    Q_EMIT pCurrentIndexChanged();
}

int ElaRoller::getCurrentIndex() const {
    Q_D(const ElaRoller);
    return d->_pCurrentIndex;
}

void ElaRoller::wheelEvent(QWheelEvent *event) {
    Q_D(ElaRoller);
    d->_scroll(event->angleDelta().y());
    event->accept();
}

void ElaRoller::mouseReleaseEvent(QMouseEvent *event) {
    Q_D(ElaRoller);
    int centerIndex = d->_pMaxVisibleItems / 2;
    int clickIndex  = event->pos().y() / d->_pItemHeight;
    int jumpCount   = abs(d->_pMaxVisibleItems / 2 - clickIndex);
    if (clickIndex > centerIndex) {
        for (int i = 0; i < jumpCount; i++) {
            d->_scroll(-120);
        }
    } else if (clickIndex < centerIndex) {
        for (int i = 0; i < jumpCount; i++) {
            d->_scroll(120);
        }
    }
}

void ElaRoller::mouseMoveEvent(QMouseEvent *event) {
    Q_D(ElaRoller);
    d->_mousePoint = event->pos();
    update();
    QWidget::mouseMoveEvent(event);
}

void ElaRoller::leaveEvent(QEvent *event) {
    Q_D(ElaRoller);
    d->_mousePoint = QPoint();
    update();
    QWidget::leaveEvent(event);
}

void ElaRoller::paintEvent(QPaintEvent *event) {
    Q_D(ElaRoller);
    QPainter painter(this);
    painter.save();
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    // 背景绘制
    QRect foregroundRect(d->_penBorderWidth, d->_penBorderWidth, width() - 2 * d->_penBorderWidth, height() - 2 * d->_penBorderWidth);
    painter.setPen(QPen(ElaThemeColor(d->_themeMode, BasicBorder), d->_penBorderWidth));
    painter.setBrush(isEnabled() ? ElaThemeColor(d->_themeMode, BasicBase) : ElaThemeColor(d->_themeMode, BasicDisable));
    painter.drawRoundedRect(foregroundRect, d->_pBorderRadius, d->_pBorderRadius);

    // 中心指示区域绘制
    painter.setPen(Qt::NoPen);
    painter.setBrush(ElaThemeColor(d->_themeMode, PrimaryNormal));
    bool isEven = d->_pMaxVisibleItems % 2 == 0;
    if (isEven) {
        painter.drawRoundedRect(QRect(d->_indicatorMargin, d->_pItemHeight * d->_pMaxVisibleItems / 2 + d->_indicatorMargin,
                                      width() - 2 * d->_indicatorMargin, d->_pItemHeight - 2 * d->_indicatorMargin),
                                d->_pBorderRadius, d->_pBorderRadius);
    } else {
        painter.drawRoundedRect(QRect(d->_indicatorMargin, (height() - d->_pItemHeight) / 2 + d->_indicatorMargin, width() - 2 * d->_indicatorMargin,
                                      d->_pItemHeight - 2 * d->_indicatorMargin),
                                d->_pBorderRadius, d->_pBorderRadius);
    }

    int yStart           = -d->_pItemHeight;
    int yEnd             = height();
    int centerYStart     = isEven ? d->_pItemHeight * d->_pMaxVisibleItems / 2 : height() / 2 - d->_pItemHeight;
    int centerYEnd       = isEven ? d->_pItemHeight * d->_pMaxVisibleItems / 2 + d->_pItemHeight / 2 : height() / 2;
    int startIndexOffset = d->_pMaxVisibleItems / 2;
    for (int i = 0; i < d->_pItemList.size(); i++) {
        qreal y = (i + startIndexOffset) * d->_pItemHeight - d->_pScrollOffset;
        // 范围控制
        while (y <= yStart) {
            y += d->_pItemList.size() * d->_pItemHeight;
        }
        while (y >= yEnd) {
            y -= d->_pItemList.size() * d->_pItemHeight;
        }
        // 可见区域绘制
        if (y >= yStart && y <= yEnd) {
            painter.save();
            painter.translate(0, y);
            // 文字绘制
            if (y >= centerYStart && y <= centerYEnd) {
                painter.setPen(ElaThemeColor(d->_themeMode, BasicTextInvert));
            } else {
                // 覆盖效果绘制
                if (!d->_mousePoint.isNull() && d->_scrollAnimation->state() == QPropertyAnimation::State::Stopped) {
                    QRectF itemRect = QRectF(0, y, width(), d->_pItemHeight);
                    if (itemRect.contains(d->_mousePoint)) {
                        painter.setBrush(ElaThemeColor(d->_themeMode, BasicHover));
                        painter.drawRoundedRect(QRect(d->_indicatorMargin, d->_indicatorMargin, width() - 2 * d->_indicatorMargin,
                                                      d->_pItemHeight - 2 * d->_indicatorMargin),
                                                d->_pBorderRadius, d->_pBorderRadius);
                    }
                }
                painter.setPen(ElaThemeColor(d->_themeMode, BasicText));
            }
            painter.drawText(QRect(0, 0, width(), d->_pItemHeight), Qt::AlignCenter | Qt::TextSingleLine, d->_pItemList[i]);
            painter.restore();
        }
    }
    painter.restore();
}
