// SPDX-FileCopyrightText: 2023 g10 Code GmbH
// SPDX-FileContributor: Sune Stolborg Vuorela <sune@vuorela.dk>
// SPDX-FileContributor: Carl Schwan <carl.schwan@gnupg.com>
// SPDX-License-Identifier: GPL-3.0-or-later

#include "qrcodepopup.h"

#include <QGraphicsDropShadowEffect>
#include <QKeyEvent>
#include <QLabel>
#include <QMainWindow>
#include <QStatusBar>
#include <QToolBar>
#include <QVBoxLayout>

#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
#include <Prison/Barcode>
#else
#include <Prison/AbstractBarcode>
#include <Prison/prison.h>
#endif

// SPDX-SnippetBegin
// Part of KConfigWidgets KCommandBar
// SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
// SPDX-License-Identifier: LGPL-2.0-or-later
static QRect getParentBoundingRect(QWidget *widget)
{
    QWidget *parentWidget = widget->parentWidget();
    Q_ASSERT(parentWidget);

    const QMainWindow *mainWindow = qobject_cast<const QMainWindow *>(parentWidget);
    if (!mainWindow) {
        return parentWidget->geometry();
    }

    QRect boundingRect = mainWindow->contentsRect();

    // exclude the menu bar from the bounding rect
    if (const QWidget *menuWidget = mainWindow->menuWidget()) {
        if (!menuWidget->isHidden()) {
            boundingRect.setTop(boundingRect.top() + menuWidget->height());
        }
    }

    // exclude the status bar from the bounding rect
    if (const QStatusBar *statusBar = mainWindow->findChild<QStatusBar *>()) {
        if (!statusBar->isHidden()) {
            boundingRect.setBottom(boundingRect.bottom() - statusBar->height());
        }
    }

    // exclude any undocked toolbar from the bounding rect
    const QList<QToolBar *> toolBars = mainWindow->findChildren<QToolBar *>();
    for (QToolBar *toolBar : toolBars) {
        if (toolBar->isHidden() || toolBar->isFloating()) {
            continue;
        }

        switch (mainWindow->toolBarArea(toolBar)) {
        case Qt::TopToolBarArea:
            boundingRect.setTop(std::max(boundingRect.top(), toolBar->geometry().bottom()));
            break;
        case Qt::RightToolBarArea:
            boundingRect.setRight(std::min(boundingRect.right(), toolBar->geometry().left()));
            break;
        case Qt::BottomToolBarArea:
            boundingRect.setBottom(std::min(boundingRect.bottom(), toolBar->geometry().top()));
            break;
        case Qt::LeftToolBarArea:
            boundingRect.setLeft(std::max(boundingRect.left(), toolBar->geometry().right()));
            break;
        default:
            break;
        }
    }

    return boundingRect;
}
// SPDX-SnippetEnd

QrCodePopup::QrCodePopup(const QString &value, QWidget *parent)
    : QFrame(parent)
{
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
    auto barcode = Prison::Barcode::create(Prison::QRCode);
#else
    auto barcode = Prison::createBarcode(Prison::BarcodeType::QRCode);
#endif
    if (!barcode) {
        return;
    }
    barcode->setData(value);
    auto image = barcode->toImage(barcode->preferredSize(window()->devicePixelRatioF()));

    setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
    setProperty("_breeze_force_frame", true);

    QGraphicsDropShadowEffect *e = new QGraphicsDropShadowEffect(this);
    e->setColor(palette().color(QPalette::Dark));
    e->setOffset(0, 4);
    e->setBlurRadius(48);
    setGraphicsEffect(e);

    QVBoxLayout *layout = new QVBoxLayout;
    QLabel *popupLabel = new QLabel();
    layout->addWidget(popupLabel);
    popupLabel->setPixmap(QPixmap::fromImage(image));
    popupLabel->setScaledContents(true);
    popupLabel->show();
    setLayout(layout);

    parent->installEventFilter(this);
}

void QrCodePopup::show()
{
    const QRect boundingRect = getParentBoundingRect(this);

    const QSize size{250, 250};
    setFixedSize(size);

    // set the position to the top-center of the parent
    // just below the menubar/toolbar (if any)
    const QPoint position{boundingRect.center().x() - size.width() / 2, boundingRect.center().y() - size.height() / 2};
    move(position);

    setFocus();
    QWidget::show();
}

bool QrCodePopup::event(QEvent *event)
{
    if (event->type() == QEvent::KeyPress || event->type() == QEvent::ShortcutOverride) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key_Escape) {
            hide();
            deleteLater();
            return true;
        }
    }
    if (event->type() == QEvent::FocusOut) {
        deleteLater();
        hide();
        return true;
    }

    return QFrame::event(event);
}

bool QrCodePopup::eventFilter(QObject *obj, QEvent *event)
{
    if (parent() == obj && event->type() == QEvent::Resize) {
        show();
    }

    return QFrame::eventFilter(obj, event);
}
