#include "NotifyManager.h"

#include "NotifyWidget.h"  // NotifyWidget.h没有放到NotifyManager.h文件，是因为NotifyWidget.cpp也include了NotifyManager.h，为了能互相include才这么做

NotifyManager::NotifyManager(QWidget *widget, QObject *parent)
    : m_parentWidget(widget), QObject(parent) {
    m_maxCount = 5;  // 可见的最大通知数目设置为5
    m_displayTime =
        3000;  // 显示时间默认设置为3秒，通知显示出来过了10秒之后隐藏并自动销毁
    m_animateTime = 300;               // 动画时间设置为300ms
    m_spacing = 10;                    // 通知框之间的间距设置为10
    m_notifyWndSize = QSize(300, 40);  // 通知框大小
    m_defaultIcon = ":/message1.png";  // 默认图标
    initStyleSheet();
    m_isShowQueueCount = true;  // 默认显示队列的通知数目

    // 传入边距以设置最下面的通知的右下角坐标
    this->setCornerMargins(10, 10);

    // 初始化队列的剩余通知数目界面
    m_notifyCount = new NotifyCountWidget(this, m_parentWidget);
}

// 弹出通知框
void NotifyManager::notify(const QString &title, const QString &body, int type,
                           int displayTime, const QVariantMap &data) {
    // 将标题栏和内容数据添加到队列中
    QVariantMap tmp = data;
    tmp.insert("title", title);
    tmp.insert("body", body);
    // tmp.insert("type", type);
    switch (type) {
        case NotificationType::SUCCESS:
            m_defaultIcon = ":/success.png";
            tmp.insert("theme", "success");
            break;
        case NotificationType::WARNING:
            m_defaultIcon = ":/warning.png";
            tmp.insert("theme", "warn");
            break;
        case NotificationType::ERROR:
            m_defaultIcon = ":/error.png";
            tmp.insert("theme", "error");
            break;
        default:
            break;
    }
    setDisplayTime(displayTime);
    m_dataQueue.enqueue(tmp);

    // 显示下一条通知
    showNext();
}

// 设置通知框的最大数目
void NotifyManager::setMaxCount(int count) {
    m_maxCount = count;
}

// 获取通知框显示时间
int NotifyManager::displayTime() const {
    return m_displayTime;
}

// 设置通知框显示时间
void NotifyManager::setDisplayTime(int displayTime) {
    m_displayTime = displayTime;
}

// 获取动画时间
int NotifyManager::animateTime() const {
    return m_animateTime;
}

// 设置动画时间
void NotifyManager::setAnimateTime(int animateTime) {
    m_animateTime = animateTime;
}

// 获取通知栏之间的间距
int NotifyManager::spacing() const {
    return m_spacing;
}

// 设置通知栏之间的间距
void NotifyManager::setSpacing(int spacing) {
    m_spacing = spacing;
}

// 获取最下面的通知的右下角坐标
QPoint NotifyManager::cornerPos() {
    QScreen *screen = QGuiApplication::primaryScreen();
    QRect screenGeometry = screen->availableGeometry();
    qreal dpiScale = screen->devicePixelRatio();
    QRect widgetGeometry = m_parentWidget->geometry();
    QPoint pt = widgetGeometry.topLeft();
    m_cornerPos.setX((pt.x() + m_parentWidget->width() / 2));
    m_cornerPos.setY(widgetGeometry.top() - m_notifyWndSize.height());
    return m_cornerPos;
}

// 传入边距以设置最下面的通知的右下角坐标
void NotifyManager::setCornerMargins(int right, int bottom) {
    // QRect desktopRect = QApplication::primaryScreen()->availableGeometry();
    // QPoint bottomRignt = desktopRect.bottomRight();
    // m_cornerPos = QPoint(bottomRignt.x() - right, bottomRignt.y() - bottom);
    // 获取当前屏幕的DPI和缩放比例
    QScreen *screen = QGuiApplication::primaryScreen();
    QRect screenGeometry = screen->availableGeometry();
    qreal dpiScale = screen->devicePixelRatio();

    QPoint bottomRignt;
    QPoint pt;
    QRect widgetGeometry = m_parentWidget->geometry();
    int y = widgetGeometry.top();
    QPoint lpt = widgetGeometry.topLeft();
    pt = m_parentWidget->mapToGlobal(lpt);
    bottomRignt.setX((screenGeometry.width() - m_parentWidget->width()) / 2);
    bottomRignt.setY((screenGeometry.height()) / 2);
    m_cornerPos =
        QPoint(bottomRignt.x() * dpiScale, bottomRignt.y() * dpiScale);
}

// 获取通知框的尺寸
QSize NotifyManager::notifyWndSize() const {
    return m_notifyWndSize;
}

// 设置通知框的尺寸
void NotifyManager::setNotifyWndSize(int width, int height) {
    m_notifyWndSize = QSize(width, height);
}

// 获取默认图标的路径
QString NotifyManager::defaultIcon() const {
    return m_defaultIcon;
}

// 设置默认图标
void NotifyManager::setDefaultIcon(const QString &defaultIcon) {
    m_defaultIcon = defaultIcon;
}

// 获取指定theme的样式
QString NotifyManager::styleSheet(const QString &theme) const {
    if (!m_styleSheets.contains(theme)) return m_styleSheets.value("default");

    return m_styleSheets.value(theme);
}

// 设置指定theme的样式
void NotifyManager::setStyleSheet(const QString &styleSheet,
                                  const QString &theme) {
    m_styleSheets[theme] = styleSheet;
}

// 设置是否显示队列的通知数目
void NotifyManager::setShowQueueCount(bool isShowQueueCount) {
    m_isShowQueueCount = isShowQueueCount;

    if (!m_isShowQueueCount) m_notifyCount->showArranged(0);
}

// 显示下一条通知
void NotifyManager::showNext() {
    // 如果通知数目超出限制，则显示"通知当前数目界面"
    if (m_notifyList.size() >= m_maxCount || m_dataQueue.isEmpty()) {
        showQueueCount();
        return;
    }

    // 创建并显示新的通知框
    NotifyWidget *notifyWidget =
        new NotifyWidget(this);  // 将管理员自身传给notifyWidget的m_manager
    m_notifyList.append(notifyWidget);  // 添加到通知框列表
    notifyWidget->showArranged(m_notifyList.size());  // 设置新通知的显示位置
    notifyWidget->setData(
        m_dataQueue
            .dequeue());  // 设置数据队列的第一个数据(dequeue，删除队列第一个元素，并返回这个元素)
    showQueueCount();     // 显示队列的剩余通知数目

    // 通知过了displayTime时间之后隐藏之后销毁，然后触发下面槽函数
    connect(notifyWidget, &QObject::destroyed, this, [notifyWidget, this]() {
        // 找到被销毁的通知在队列中的索引，然后移除该通知
        int index = m_notifyList.indexOf(notifyWidget);
        m_notifyList.removeAt(index);

        // 旧消息被移出后，就要显示通知队列中的下一个新消息，并排序
        for (; index < m_notifyList.size(); index++)
            m_notifyList[index]->showArranged(index + 1);

        // 这里是为了实现周期提示功能，一般不用到，可以注释
        QTimer::singleShot(m_animateTime, this, [this]() {
            showNext();
        });
    });
}

// 显示队列的剩余通知数目
void NotifyManager::showQueueCount() {
    // 判断是否允许显示队列的剩余通知数目
    if (!m_isShowQueueCount) return;

    // 数据队列大于0，说明还有未显示的剩余通知，则显示数目；否则隐藏"剩余通知数目"
    if (!m_dataQueue.isEmpty()) {
        m_notifyCount->showArranged(m_maxCount + 1);
        m_notifyCount->setCount(m_dataQueue.size());
    } else {
        m_notifyCount->showArranged(0);
    }
}

void NotifyManager::initStyleSheet() {
    m_styleSheets["default"] =
        "#notify-background {"
        "background: white;"
        "border-radius: 6px;"
        "}"
        "#notify-title{"
        "font-weight: bold;"
        "font-size: 14px;"
        "color: #333333;"
        "}"
        "#notify-body{"
        "font-size: 12px;"
        "color: #444444;"
        "}"
        "#notify-close-btn{ "
        "border: 0;"
        "color: #999999;"
        "}"
        "#notify-close-btn:hover{ "
        "background: #cccccc;"
        "}";

    m_styleSheets["success"] =
        "#notify-background {"
        "background: rgba(236, 253, 245, 0.95);"
        "border-radius: 6px;"
        "border: 1px solid #A7F3D0;"
        "}"
        "#notify-title{"
        "font-weight: bold;"
        "font-size: 14px;"
        "color: #059669;"
        "}"
        "#notify-body{"
        "font-size: 12px;"
        "color: #059669;"
        "}"
        "#notify-close-btn{ "
        "border: 0;"
        "color: #059669;"
        "}"
        "#notify-close-btn:hover{ "
        "background: #D1FAE5;"
        "}";

    m_styleSheets["warn"] =
        "#notify-background {"
        "background: rgba(254, 252, 232, 0.95);"
        "border-radius: 6px;"
        "border: 1px solid #FEF08A;"
        "}"
        "#notify-title{"
        "font-weight: bold;"
        "font-size: 14px;"
        "color: #D97706;"
        "}"
        "#notify-body{"
        "font-size: 12px;"
        "color: #D97706;"
        "}"
        "#notify-close-btn{ "
        "border: 0;"
        "color: #D97706;"
        "}"
        "#notify-close-btn:hover{ "
        "background: #FEF9C3;"
        "}";

    m_styleSheets["error"] =
        "#notify-background {"
        "background: rgba(254, 242, 242, 0.95);"
        "border-radius: 6px;"
        "border: 1px solid #FECACA;"
        "}"
        "#notify-title{"
        "font-weight: bold;"
        "font-size: 14px;"
        "color: #DC2626;"
        "}"
        "#notify-body{"
        "font-size: 12px;"
        "color: #DC2626;"
        "}"
        "#notify-close-btn{ "
        "border: 0;"
        "color: #DC2626;"
        "}"
        "#notify-close-btn:hover{ "
        "background: #FEE2E2;"
        "}";
}
