#include "maskoverlay.h"

#include <QApplication>
#include <QGraphicsOpacityEffect>
#include <QPainter>
#include <QPropertyAnimation>
#include <QResizeEvent>
#include <QScreen>
#include <QVBoxLayout>
#include "qdebug.h"

MaskOverlay* MaskOverlay::instance_ = nullptr;

MaskOverlay* MaskOverlay::instance()
{
    if (!instance_) {
        instance_ = new MaskOverlay(qApp);
    }
    return instance_;
}

MaskOverlay::MaskOverlay(QObject* parent)
    : QObject(parent)
    , globalStyle_("background-color: rgba(0, 0, 0, 128);")
    , progressStyle_("QProgressBar {"
                     "   border: 2px solid #555;"
                     "   border-radius: 5px;"
                     "   background: rgba(255, 255, 255, 150);"
                     "}"
                     "QProgressBar::chunk {"
                     "   background-color: #05B8CC;"
                     "   border-radius: 3px;"
                     "}")
{}

QWidget* MaskOverlay::findBestTarget(QWidget* hintTarget, FindMode mode)
{
    if (hintTarget)
        return hintTarget;

    switch (mode) {
    case ActiveWindow:
        return QApplication::activeWindow();
    case MainWindow: {
        foreach (QWidget* w, QApplication::topLevelWidgets()) {
            if (w->isWindow() && w->windowType() == Qt::Window) {
                return w;
            }
        }
        return nullptr;
    }
    case ParentWindow:
        return qobject_cast<QWidget*>(parent());
    default:
        return nullptr;
    }
}

void MaskOverlay::show(QWidget* target,
                       int timeoutMs,
                       FindMode findMode,
                       std::function<void()> timeoutCallback)
{
    QWidget* actualTarget = findBestTarget(target, findMode);
    if (!actualTarget) {
        qWarning() << "No suitable target window found";
        return;
    }

    if (overlays_.contains(actualTarget))
        return;

    setupOverlay(actualTarget);
    OverlayContext& ctx = overlays_[actualTarget];

    // 渐显动画
    QGraphicsOpacityEffect* effect = new QGraphicsOpacityEffect(ctx.maskWidget);
    ctx.maskWidget->setGraphicsEffect(effect);
    QPropertyAnimation* anim = new QPropertyAnimation(effect, "opacity");
    anim->setDuration(300);
    anim->setStartValue(0);
    anim->setEndValue(1);
    anim->start(QPropertyAnimation::DeleteWhenStopped);

    ctx.maskWidget->show();
    ctx.maskWidget->raise();
    lastShownTarget_ = actualTarget;

    if (timeoutMs > 0) {
        ctx.timeoutTimer->setInterval(timeoutMs);
        ctx.timeoutTimer->start();
        ctx.timeoutCallback = timeoutCallback;
    }
}

void MaskOverlay::hide(QWidget* target)
{
    QWidget* actualTarget = target ? target : lastShownTarget_.data();
    if (!actualTarget)
        actualTarget = findBestTarget(nullptr, ActiveWindow);
    if (!actualTarget || !overlays_.contains(actualTarget))
        return;

    OverlayContext ctx = overlays_.take(actualTarget);
    ctx.timeoutTimer->stop();

    // 渐隐动画
    QGraphicsOpacityEffect* effect = new QGraphicsOpacityEffect(ctx.maskWidget);
    ctx.maskWidget->setGraphicsEffect(effect);
    QPropertyAnimation* anim = new QPropertyAnimation(effect, "opacity");
    anim->setDuration(300);
    anim->setStartValue(1);
    anim->setEndValue(0);
    connect(anim, &QPropertyAnimation::finished, [ctx]() {
        ctx.maskWidget->deleteLater();
        ctx.progressBar->deleteLater();
        ctx.timeoutTimer->deleteLater();
    });
    anim->start(QPropertyAnimation::DeleteWhenStopped);
}

void MaskOverlay::setupOverlay(QWidget* target)
{
    if (!target || overlays_.contains(target))
        return;

    OverlayContext ctx;
    ctx.maskWidget = new QWidget(target);
    ctx.maskWidget->setStyleSheet(globalStyle_);
    ctx.maskWidget->setAttribute(Qt::WA_TransparentForMouseEvents, false);
    ctx.maskWidget->resize(target->size());

    ctx.progressBar = new QProgressBar(ctx.maskWidget);
    ctx.progressBar->setStyleSheet(progressStyle_);
    ctx.progressBar->setRange(0, 0);
    ctx.progressBar->setFixedSize(200, 20);

    QVBoxLayout* layout = new QVBoxLayout(ctx.maskWidget);
    layout->addWidget(ctx.progressBar, 0, Qt::AlignCenter);

    ctx.timeoutTimer = new QTimer(this);
    ctx.timeoutTimer->setSingleShot(true);
    connect(ctx.timeoutTimer, &QTimer::timeout, [this, target]() {
        if (overlays_.contains(target)) {
            if (overlays_[target].timeoutCallback) {
                overlays_[target].timeoutCallback();
            }
            this->hide(target);
        }
    });

    target->installEventFilter(this);
    overlays_.insert(target, ctx);
}

bool MaskOverlay::eventFilter(QObject* watched, QEvent* event)
{
    QWidget* target = qobject_cast<QWidget*>(watched);
    if (!target)
        return false;

    if (event->type() == QEvent::Resize) {
        if (overlays_.contains(target)) {
            overlays_[target].maskWidget->resize(target->size());
        }
    } else if (event->type() == QEvent::Close) {
        hide(target);
    }

    return QObject::eventFilter(watched, event);
}

void MaskOverlay::setGlobalStyle(const QString& styleSheet)
{
    globalStyle_ = styleSheet;
    for (auto& ctx : overlays_) {
        ctx.maskWidget->setStyleSheet(globalStyle_);
    }
}

void MaskOverlay::setProgressBarStyle(const QString& styleSheet)
{
    progressStyle_ = styleSheet;
    for (auto& ctx : overlays_) {
        ctx.progressBar->setStyleSheet(progressStyle_);
    }
}

void MaskOverlay::setProgressValue(QWidget* target, int value)
{
    QWidget* actualTarget = target ? target : lastShownTarget_.data();
    if (!actualTarget || !overlays_.contains(actualTarget))
        return;

    OverlayContext& ctx = overlays_[actualTarget];
    ctx.progressBar->setRange(0, 100); // 设置为确定模式
    ctx.progressBar->setValue(value);
}

void MaskOverlay::setTimeout(QWidget* target, int milliseconds)
{
    if (target && overlays_.contains(target)) {
        overlays_[target].timeoutTimer->setInterval(milliseconds);
    }
}
