#include "SARibbonSystemButtonBar.h"
#include <QToolButton>
#include <QResizeEvent>
#include <QStyle>
#include <QDebug>
#include <QScopedPointer>
#include <QWindowStateChangeEvent>
#include "SARibbonMainWindow.h"
#include "SARibbonBar.h"
#include "SARibbonElementManager.h"
#include "SARibbonButtonGroupWidget.h"

// 为了避免使用此框架的app设置了全局的qpushbutton 的 qss样式影响此按钮，定义了一个类

/**
 * @brief The SARibbonSystemButtonBar class
 */
class SARibbonSystemButtonBar::PrivateData
{
    SA_RIBBON_DECLARE_PUBLIC(SARibbonSystemButtonBar)
public:
    SARibbonSystemToolButton* buttonClose { nullptr };
    SARibbonSystemToolButton* buttonMinimize { nullptr };
    SARibbonSystemToolButton* buttonMaximize { nullptr };
    int mCloseStretch { 4 };
    int mMaxStretch { 3 };
    int mMinStretch { 3 };
    int mWindowButtonWidth { 35 };
    int mTitleBarHeight { 28 };
    Qt::WindowFlags mFlags { Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint };
    SARibbonButtonGroupWidget* mButtonGroup;

public:
    PrivateData(SARibbonSystemButtonBar* p) : q_ptr(p)
    {
        mButtonGroup = new SARibbonButtonGroupWidget(p);
        mButtonGroup->setObjectName("SASystemButtonGroup");
    }

    void setupMinimizeButton(bool on)
    {
        SARibbonSystemButtonBar* par = q_ptr;

        if (on) {
            if (buttonMinimize) {
                buttonMinimize->deleteLater();
                buttonMinimize = nullptr;
            }
            buttonMinimize = new SARibbonSystemToolButton(par);
            buttonMinimize->setObjectName(QStringLiteral("SAMinimizeWindowButton"));
            buttonMinimize->setFocusPolicy(Qt::NoFocus);  // 避免铺抓到
            buttonMinimize->show();
            par->connect(buttonMinimize, &QAbstractButton::clicked, par, &SARibbonSystemButtonBar::minimizeWindow);
        } else {
            if (buttonMinimize) {
                buttonMinimize->deleteLater();
                buttonMinimize = nullptr;
            }
        }
        updateSize();
    }

    void setupMaximizeButton(bool on)
    {
        SARibbonSystemButtonBar* par = q_ptr;

        if (on) {
            if (buttonMaximize) {
                buttonMaximize->deleteLater();
                buttonMaximize = nullptr;
            }
            buttonMaximize = new SARibbonSystemToolButton(par);
            buttonMaximize->setObjectName(QStringLiteral("SAMaximizeWindowButton"));
            buttonMaximize->setCheckable(true);
            buttonMaximize->setFocusPolicy(Qt::NoFocus);  // 避免铺抓到
            //            buttonMaximize->setIconSize(buttonMaximize->size() * mIconscale);
            buttonMaximize->show();
            par->connect(buttonMaximize, &QAbstractButton::clicked, par, &SARibbonSystemButtonBar::maximizeWindow);
        } else {
            if (buttonMaximize) {
                buttonMaximize->deleteLater();
                ;
                buttonMaximize = nullptr;
            }
        }
        updateSize();
    }

    void setupCloseButton(bool on)
    {
        SARibbonSystemButtonBar* par = q_ptr;

        if (on) {
            if (buttonClose) {
                buttonClose->deleteLater();
                buttonClose = nullptr;
            }
            buttonClose = new SARibbonSystemToolButton(par);
            buttonClose->setObjectName(QStringLiteral("SACloseWindowButton"));
            buttonClose->setFocusPolicy(Qt::NoFocus);  // 避免铺抓到
            // buttonClose->setFlat(true);
            par->connect(buttonClose, &QAbstractButton::clicked, par, &SARibbonSystemButtonBar::closeWindow);
            //            buttonClose->setIconSize(buttonClose->size() * mIconscale);
            buttonClose->show();
        } else {
            if (buttonClose) {
                buttonClose->deleteLater();
                ;
                buttonClose = nullptr;
            }
        }
        updateSize();
    }

    void updateSize()
    {
        resizeElement(q_ptr->size());
    }

    void resizeElement(QSize size)
    {
        int x = size.width();
        if (buttonClose) {
            int w = closeButtonWidthHint();
            x -= w;
            buttonClose->setGeometry(x, 0, w, size.height());
        }
        if (buttonMaximize) {
            int w = maxButtonWidthHint();
            x -= w;
            buttonMaximize->setGeometry(x, 0, w, size.height());
        }
        if (buttonMinimize) {
            int w = minButtonWidthHint();
            x -= w;
            buttonMinimize->setGeometry(x, 0, w, size.height());
        }
        if (mButtonGroup) {
            mButtonGroup->setGeometry(0, 0, x, size.height());
        }
    }

    int closeButtonWidthHint() const
    {
        qreal t = mCloseStretch + mMaxStretch + mMinStretch;
        return (mCloseStretch * (3 * mWindowButtonWidth)) / t;
    }

    int maxButtonWidthHint() const
    {
        qreal t = mCloseStretch + mMaxStretch + mMinStretch;
        return (mMaxStretch * (3 * mWindowButtonWidth)) / t;
    }

    int minButtonWidthHint() const
    {
        qreal t = mCloseStretch + mMaxStretch + mMinStretch;
        return (mMinStretch * (3 * mWindowButtonWidth)) / t;
    }

    QSize sizeHint() const
    {
        int height = mTitleBarHeight;
        if (height < 20) {
            height = 20;
        }
        QSize res(0, 0);
        if (mButtonGroup) {
            res = mButtonGroup->sizeHint();
        }
        res.setHeight(height);
        if (buttonClose) {
            res.setWidth(res.width() + closeButtonWidthHint());
        }
        if (buttonMaximize) {
            res.setWidth(res.width() + maxButtonWidthHint());
        }
        if (buttonMinimize) {
            res.setWidth(res.width() + minButtonWidthHint());
        }
        return res;
    }
};

//===================================================
// SARibbonSystemToolButton
//===================================================
SARibbonSystemToolButton::SARibbonSystemToolButton(QWidget* p) : QToolButton(p)
{
    setAutoRaise(true);
}
//===================================================
// SARibbonSystemButtonBar
//===================================================
SARibbonSystemButtonBar::SARibbonSystemButtonBar(QWidget* parent)
    : QFrame(parent), d_ptr(new SARibbonSystemButtonBar::PrivateData(this))
{
    updateWindowFlag();
}

/**
 * @brief 构造函数，强制使用flags，而不是用parent的flags进行构造
 * @param parent
 * @param flags
 */
SARibbonSystemButtonBar::SARibbonSystemButtonBar(QWidget* parent, Qt::WindowFlags flags)
    : QFrame(parent), d_ptr(new SARibbonSystemButtonBar::PrivateData(this))
{
    d_ptr->mFlags = flags;
    updateWindowFlag();
}

SARibbonSystemButtonBar::~SARibbonSystemButtonBar()
{
}

void SARibbonSystemButtonBar::setupMinimizeButton(bool on)
{
    d_ptr->setupMinimizeButton(on);
}

void SARibbonSystemButtonBar::setupMaximizeButton(bool on)
{
    d_ptr->setupMaximizeButton(on);
}

void SARibbonSystemButtonBar::setupCloseButton(bool on)
{
    d_ptr->setupCloseButton(on);
}

void SARibbonSystemButtonBar::updateWindowFlag()
{
    QWidget* topedWidget = this;
    // 找到最顶层窗口
    while (topedWidget->parentWidget()) {
        topedWidget = topedWidget->parentWidget();
    }
    Qt::WindowFlags flags = topedWidget->windowFlags();
    updateWindowFlag(flags);
}

/**
 * @brief 此函数仅用于控制最小最大化和关闭按钮的显示
 * @param flags
 */
void SARibbonSystemButtonBar::updateWindowFlag(Qt::WindowFlags flags)
{
    d_ptr->mFlags = flags;
    setupMinimizeButton(flags & Qt::WindowMinimizeButtonHint);
    setupMaximizeButton(flags & Qt::WindowMaximizeButtonHint);
    setupCloseButton(flags & Qt::WindowCloseButtonHint);
}

/**
 * @brief 设置按钮的宽度比例,最终按钮宽度将按照此比例进行设置
 * @param close 关闭按钮比例
 * @param max 最大化按钮比例
 * @param min 最小化按钮比例
 */
void SARibbonSystemButtonBar::setButtonWidthStretch(int close, int max, int min)
{
    d_ptr->mMaxStretch   = max;
    d_ptr->mMinStretch   = min;
    d_ptr->mCloseStretch = close;
}

/**
 * @brief 标题栏高度
 *
 * 标题栏高度会影响sizeHint
 * @param h
 */
void SARibbonSystemButtonBar::setWindowTitleHeight(int h)
{
    d_ptr->mTitleBarHeight = h;
}

/**
 * @brief 标题栏高度
 * @return
 */
int SARibbonSystemButtonBar::windowTitleHeight() const
{
    return d_ptr->mTitleBarHeight;
}

/**
 * @brief 系统按钮的宽度
 * @param w
 */
void SARibbonSystemButtonBar::setWindowButtonWidth(int w)
{
    d_ptr->mWindowButtonWidth = w;
}

/**
 * @brief 系统按钮的宽度
 * @param w
 */
int SARibbonSystemButtonBar::windowButtonWidth() const
{
    return d_ptr->mWindowButtonWidth;
}

/**
 * @brief 设置窗口状态（最大最小化按钮状态）
 * @param s
 */
void SARibbonSystemButtonBar::setWindowStates(Qt::WindowStates s)
{
    if (d_ptr->buttonMaximize) {
        bool on = s.testFlag(Qt::WindowMaximized);
        d_ptr->buttonMaximize->setChecked(on);
        d_ptr->buttonMaximize->setToolTip(on ? tr("Restore") : tr("Maximize"));
    }
}

/**
 * @brief 此函数返回的flags仅包括 Qt::WindowCloseButtonHint，Qt::WindowMaximizeButtonHint，Qt::WindowMinimizeButtonHint
 * 三个
 *
 * @return
 */
Qt::WindowFlags SARibbonSystemButtonBar::windowButtonFlags() const
{
    Qt::WindowFlags f = Qt::Widget;  // widget是000

    if (d_ptr->mFlags & Qt::WindowCloseButtonHint) {
        f |= Qt::WindowCloseButtonHint;
    }
    if (d_ptr->mFlags & Qt::WindowMaximizeButtonHint) {
        f |= Qt::WindowMaximizeButtonHint;
    }
    if (d_ptr->mFlags & Qt::WindowMinimizeButtonHint) {
        f |= Qt::WindowMinimizeButtonHint;
    }

    return (f);
}

QSize SARibbonSystemButtonBar::sizeHint() const
{
    return (d_ptr->sizeHint());
}

bool SARibbonSystemButtonBar::eventFilter(QObject* obj, QEvent* event)
{
    if (obj == parent()) {
        // SARibbonMainWindow的事件
        if (event->type() == QEvent::Resize) {
            SARibbonMainWindow* mainWindow = qobject_cast< SARibbonMainWindow* >(obj);
            if (!mainWindow) {
                // 所有事件都不消费
                return QFrame::eventFilter(obj, event);
            }
            SARibbonBar* ribbonBar = mainWindow->ribbonBar();
            if (!ribbonBar) {
                // 所有事件都不消费
                return QFrame::eventFilter(obj, event);
            }
            const int th = ribbonBar->titleBarHeight();
            if (th != height()) {
                setWindowTitleHeight(th);
            }
            QRect fr         = mainWindow->geometry();
            QSize wgSizeHint = sizeHint();
            setGeometry(fr.width() - wgSizeHint.width(), 0, wgSizeHint.width(), wgSizeHint.height());
            // 把设置好的尺寸给ribbonbar
            ribbonBar->setWindowButtonGroupSize(size());
        } else if (event->type() == QEvent::WindowStateChange) {
            SARibbonMainWindow* mainWindow = qobject_cast< SARibbonMainWindow* >(obj);
            if (!mainWindow) {
                // 所有事件都不消费
                return QFrame::eventFilter(obj, event);
            }
            setWindowStates(mainWindow->windowState());
        }
    }
    return QFrame::eventFilter(obj, event);
}

QAbstractButton* SARibbonSystemButtonBar::minimizeButton() const
{
    return d_ptr->buttonMinimize;
}

QAbstractButton* SARibbonSystemButtonBar::maximizeButton() const
{
    return d_ptr->buttonMaximize;
}

QAbstractButton* SARibbonSystemButtonBar::closeButton() const
{
    return d_ptr->buttonClose;
}

void SARibbonSystemButtonBar::setIconSize(const QSize& ic)
{
    d_ptr->mButtonGroup->setIconSize(ic);
}

QSize SARibbonSystemButtonBar::iconSize() const
{
    return d_ptr->mButtonGroup->iconSize();
}

QAction* SARibbonSystemButtonBar::addAction(QAction* a, Qt::ToolButtonStyle buttonStyle, QToolButton::ToolButtonPopupMode popMode)
{
    return d_ptr->mButtonGroup->addAction(a, buttonStyle, popMode);
}

QAction* SARibbonSystemButtonBar::addAction(const QString& text,
                                            const QIcon& icon,
                                            Qt::ToolButtonStyle buttonStyle,
                                            QToolButton::ToolButtonPopupMode popMode)
{
    return d_ptr->mButtonGroup->addAction(text, icon, buttonStyle, popMode);
}

QAction* SARibbonSystemButtonBar::addMenu(QMenu* menu, Qt::ToolButtonStyle buttonStyle, QToolButton::ToolButtonPopupMode popMode)
{
    return d_ptr->mButtonGroup->addMenu(menu, buttonStyle, popMode);
}

QAction* SARibbonSystemButtonBar::addSeparator()
{
    return d_ptr->mButtonGroup->addSeparator();
}

QAction* SARibbonSystemButtonBar::addWidget(QWidget* w)
{
    return d_ptr->mButtonGroup->addWidget(w);
}

void SARibbonSystemButtonBar::resizeEvent(QResizeEvent* e)
{
    Q_UNUSED(e);
    d_ptr->resizeElement(size());
}

void SARibbonSystemButtonBar::closeWindow()
{
    if (parentWidget()) {
        parentWidget()->close();
    }
}

void SARibbonSystemButtonBar::minimizeWindow()
{
    if (parentWidget()) {
        parentWidget()->showMinimized();
    }
}

void SARibbonSystemButtonBar::maximizeWindow()
{
    QWidget* par = parentWidget();

    if (par) {
        if (par->isMaximized()) {
            par->showNormal();
        } else {
            par->showMaximized();
        }
    }
}
