#include "rippleeffectbutton.hpp"

#include <QDebug>
#include <QPainter>

#include "singletons/thememanager.hpp"

namespace chatterino {
namespace widgets {

RippleEffectButton::RippleEffectButton(BaseWidget *parent)
    : BaseWidget(parent)
{
    connect(&effectTimer_, &QTimer::timeout, this, &RippleEffectButton::onMouseEffectTimeout);

    this->effectTimer_.setInterval(20);
    this->effectTimer_.start();
}

void RippleEffectButton::setMouseEffectColor(boost::optional<QColor> color)
{
    this->mouseEffectColor_ = color;
}

void RippleEffectButton::setPixmap(const QPixmap &_pixmap)
{
    this->pixmap_ = _pixmap;
    this->update();
}

const QPixmap &RippleEffectButton::getPixmap() const
{
    return this->pixmap_;
}

void RippleEffectButton::setBorderColor(const QColor &color)
{
    this->borderColor_ = color;
}

const QColor &RippleEffectButton::getBorderColor() const
{
    return this->borderColor_;
}

void RippleEffectButton::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    painter.setRenderHint(QPainter::SmoothPixmapTransform);

    this->fancyPaint(painter);

    if (!this->pixmap_.isNull()) {
        QRect rect = this->rect();
        int s = int(6 * this->getScale());

        rect.moveLeft(s);
        rect.setRight(rect.right() - s - s);
        rect.moveTop(s);
        rect.setBottom(rect.bottom() - s - s);

        painter.drawPixmap(rect, this->pixmap_);
    }

    if (this->borderColor_.isValid()) {
        painter.setRenderHint(QPainter::Antialiasing, false);
        painter.setPen(this->borderColor_);
        painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
    }
}

void RippleEffectButton::fancyPaint(QPainter &painter)
{
    painter.setRenderHint(QPainter::HighQualityAntialiasing);
    painter.setRenderHint(QPainter::Antialiasing);
    QColor c;

    if (this->mouseEffectColor_) {
        c = this->mouseEffectColor_.get();
    } else {
        c = this->themeManager->isLightTheme() ? QColor(0, 0, 0) : QColor(255, 255, 255);
    }

    if (this->hoverMultiplier_ > 0) {
        QRadialGradient gradient(mousePos_.x(), mousePos_.y(), 50, mousePos_.x(), mousePos_.y());

        gradient.setColorAt(0,
                            QColor(c.red(), c.green(), c.blue(), int(24 * this->hoverMultiplier_)));
        gradient.setColorAt(1,
                            QColor(c.red(), c.green(), c.blue(), int(12 * this->hoverMultiplier_)));

        painter.fillRect(this->rect(), gradient);
    }

    for (auto effect : this->clickEffects_) {
        QRadialGradient gradient(effect.position.x(), effect.position.y(),
                                 effect.progress * float(width()) * 2, effect.position.x(),
                                 effect.position.y());

        gradient.setColorAt(0,
                            QColor(c.red(), c.green(), c.blue(), int((1 - effect.progress) * 95)));
        gradient.setColorAt(0.9999,
                            QColor(c.red(), c.green(), c.blue(), int((1 - effect.progress) * 95)));
        gradient.setColorAt(1, QColor(c.red(), c.green(), c.blue(), int(0)));

        painter.fillRect(this->rect(), gradient);
    }
}

void RippleEffectButton::enterEvent(QEvent *)
{
    this->mouseOver_ = true;
}

void RippleEffectButton::leaveEvent(QEvent *)
{
    this->mouseOver_ = false;
}

void RippleEffectButton::mousePressEvent(QMouseEvent *event)
{
    if (event->button() != Qt::LeftButton) {
        return;
    }

    this->clickEffects_.push_back(ClickEffect(event->pos()));

    this->mouseDown_ = true;
}

void RippleEffectButton::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() != Qt::LeftButton) {
        return;
    }

    this->mouseDown_ = false;

    if (this->rect().contains(event->pos())) {
        emit clicked();
    }
}

void RippleEffectButton::mouseMoveEvent(QMouseEvent *event)
{
    this->mousePos_ = event->pos();
}

void RippleEffectButton::onMouseEffectTimeout()
{
    bool performUpdate = false;

    if (selected_) {
        if (this->hoverMultiplier_ != 0) {
            this->hoverMultiplier_ = std::max(0.0, this->hoverMultiplier_ - 0.1);
            performUpdate = true;
        }
    } else if (mouseOver_) {
        if (this->hoverMultiplier_ != 1) {
            this->hoverMultiplier_ = std::min(1.0, this->hoverMultiplier_ + 0.5);
            performUpdate = true;
        }
    } else {
        if (this->hoverMultiplier_ != 0) {
            this->hoverMultiplier_ = std::max(0.0, this->hoverMultiplier_ - 0.3);
            performUpdate = true;
        }
    }

    if (this->clickEffects_.size() != 0) {
        performUpdate = true;

        for (auto it = this->clickEffects_.begin(); it != this->clickEffects_.end();) {
            (*it).progress += mouseDown_ ? 0.02 : 0.07;

            if ((*it).progress >= 1.0) {
                it = this->clickEffects_.erase(it);
            } else {
                it++;
            }
        }
    }

    if (performUpdate) {
        update();
    }
}

}  // namespace widgets
}  // namespace chatterino
