#include "bubbletip.h"
#include <QApplication>
#include <QGraphicsOpacityEffect>
#include <QPainter>
#include <QPainterPath>
#include <QScreen>
#include <QVBoxLayout>
#include "qcolor.h"
#include "qnamespace.h"
#include <thememanager.h>

QQueue<BubbleTip*> BubbleTip::m_queue;
QMap<QWidget*, QMap<BubbleTip::Position, QQueue<BubbleTip*>>> BubbleTip::m_targetMap;

BubbleTip::BubbleTip(QWidget* target,
                     const QString& text,
                     Position position,
                     int duration,
                     Type type,
                     QWidget* parent)
    : QWidget(parent)
    , m_target(target)
    , m_position(position)
    , m_type(type)
    , m_label(new QLabel(text, this))
    , m_timer(new QTimer(this))
    , m_verticalOffset(0)
{
    setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint);
    setAttribute(Qt::WA_TranslucentBackground);
    setAttribute(Qt::WA_ShowWithoutActivating);

    m_label->setAlignment(Qt::AlignCenter);

    QString textColor;
    switch (m_type) {
    case Success:
        textColor = "colorSuccess";
        break;
    case Warning:
        textColor = "colorWarning";
        break;
    case Error:
        textColor = "colorError";
        break;
    case Info:
        textColor = "colorInfo";
        break;
    default:
        textColor = "colorText";
        break;
    }
    textColor = "colorText";
    m_label->setStyleSheet(
        QString("color: %1;").arg(ThemeManager::instance().color(textColor).name()));

    QVBoxLayout* layout = new QVBoxLayout(this);
    layout->setContentsMargins(10, 8, 10, 8);
    layout->addWidget(m_label);
    setLayout(layout);

    if (m_target) {
        m_target->installEventFilter(this);
        m_targetMap[m_target][m_position].enqueue(this);
    }

    adjustSize();
    updatePosition();
    startShowAnimation();

    if (duration > 0) {
        m_timer->setSingleShot(true);
        connect(m_timer, &QTimer::timeout, this, &BubbleTip::startHideAnimation);
        m_timer->start(duration);
    }

    m_queue.enqueue(this);
    adjustTipsForTarget(m_target); // 关键：立即调整所有提示的位置
}

void BubbleTip::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    // 获取背景和边框颜色
    QColor bgColor = ThemeManager::instance().color("colorBgElevated");
    QColor borderColor;

    // 根据类型选择边框颜色
    switch (m_type) {
    case Success:
        borderColor = ThemeManager::instance().color("colorSuccessBorder");
        break;
    case Warning:
        borderColor = ThemeManager::instance().color("colorWarningBorder");
        break;
    case Error:
        borderColor = ThemeManager::instance().color("colorErrorBorder");
        break;
    case Info:
        borderColor = ThemeManager::instance().color("colorInfoBorder");
        break;
    default:
        borderColor = ThemeManager::instance().color("colorBorder");
        break;
    }

    // 绘制背景
    QPainterPath path;
    path.addRoundedRect(rect(), 8, 8);

    // 添加轻微阴影效果
    // painter.setPen(Qt::NoPen);
    // painter.setBrush(QColor(0, 0, 0, 15));
    // painter.drawRoundedRect(rect().adjusted(2, 2, 2, 2), 8, 8);

    // 绘制主体
    painter.fillPath(path, bgColor);

    // 绘制边框
    QPen pen(borderColor);
    pen.setWidth(1);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);
    painter.drawPath(path);

    // 如果是有类型的提示，添加左侧彩色条
    if (m_type != Default) {
        QRect indicatorRect = QRect(rect().left() + 1, rect().top() + 1, 4, rect().height() - 2);
        QPainterPath indicatorPath;
        indicatorPath.addRoundedRect(indicatorRect, 2, 2);
        painter.fillPath(indicatorPath, borderColor);
    }
}

void BubbleTip::updatePosition()
{
    if (!m_target)
        return;

    const int spacing = 5;
    QPoint basePos;

    // Step 1: 计算目标控件的全局坐标
    switch (m_position) {
    case Top:
        basePos = m_target->mapToGlobal(QPoint(0, 0));
        break;
    case Bottom:
        basePos = m_target->mapToGlobal(QPoint(0, m_target->height()));
        break;
    case Left:
        basePos = m_target->mapToGlobal(QPoint(-width(), 0));
        break;
    case Right:
        basePos = m_target->mapToGlobal(QPoint(m_target->width(), 0));
        break;
    case Center:
        basePos = m_target->mapToGlobal(QPoint(m_target->width() / 2, m_target->height() / 2));
        break;
    }

    // Step 2: 转换为父窗口坐标（如果存在父窗口）
    QWidget* parent = parentWidget();
    if (parent) {
        basePos = parent->mapFromGlobal(basePos);
    }

    // Step 3: 根据位置类型和偏移量计算最终坐标
    int x = 0, y = 0;
    switch (m_position) {
    case Top:
        x = basePos.x() + (m_target->width() - width()) / 2;
        y = basePos.y() + spacing + m_verticalOffset;
        break;
    case Bottom:
        x = basePos.x() + (m_target->width() - width()) / 2;
        y = basePos.y() - height() - spacing + m_verticalOffset;
        break;
    case Left:
        x = basePos.x() + width() + spacing;
        y = basePos.y() + (m_target->height() - height()) / 2 + m_verticalOffset;
        break;
    case Right:
        x = basePos.x() - width() - spacing;
        y = basePos.y() + (m_target->height() - height()) / 2 + m_verticalOffset;
        break;
    case Center:
        x = basePos.x() - width() / 2;
        y = basePos.y() - height() / 2 + m_verticalOffset;
        break;
    }

    // Step 4: 边界约束（防止超出屏幕）
    QRect screenGeometry = QApplication::primaryScreen()->availableGeometry();
    if (parent) {
        screenGeometry = parent->rect();
    }
    x = qMax(0, qMin(x, screenGeometry.width() - width()));
    y = qMax(0, qMin(y, screenGeometry.height() - height()));

    move(x, y);
}

void BubbleTip::startShowAnimation()
{
    QGraphicsOpacityEffect* effect = new QGraphicsOpacityEffect(this);
    setGraphicsEffect(effect);

    QPropertyAnimation* anim = new QPropertyAnimation(effect, "opacity");
    anim->setDuration(300);
    anim->setStartValue(0);
    anim->setEndValue(1);
    anim->start(QPropertyAnimation::DeleteWhenStopped);
    show();
}

void BubbleTip::startHideAnimation()
{
    QGraphicsOpacityEffect* effect = new QGraphicsOpacityEffect(this);
    setGraphicsEffect(effect);

    QPropertyAnimation* anim = new QPropertyAnimation(effect, "opacity");
    anim->setDuration(300);
    anim->setStartValue(1);
    anim->setEndValue(0);

    connect(anim, &QPropertyAnimation::finished, [this]() {
        m_queue.removeOne(this);
        m_targetMap[m_target][m_position].removeOne(this);
        adjustTipsForTarget(m_target); // 隐藏后调整剩余提示
        deleteLater();
    });

    anim->start(QPropertyAnimation::DeleteWhenStopped);
}

void BubbleTip::adjustTipsForTarget(QWidget* target)
{
    if (!target || !m_targetMap.contains(target))
        return;

    const int spacing = 8; // 统一间距
    QMap<Position, QQueue<BubbleTip*>>& positionGroups = m_targetMap[target];

    // 独立处理每个位置组
    auto adjustGroup = [&](Position pos, auto offsetCalculator) {
        if (!positionGroups.contains(pos))
            return;

        int cumulativeOffset = 0;
        for (BubbleTip* tip : positionGroups[pos]) {
            tip->m_verticalOffset = offsetCalculator(cumulativeOffset);
            cumulativeOffset += tip->height() + spacing;
            tip->updatePosition();
        }
    };

    // 顶部提示：向上堆叠（负偏移）
    adjustGroup(Top, [](int offset) { return offset; });

    // 底部提示：向下堆叠（正偏移）
    adjustGroup(Bottom, [](int offset) { return -offset; });

    // 左右提示：垂直居中偏移
    adjustGroup(Left, [](int offset) { return offset; });
    adjustGroup(Right, [](int offset) { return offset; });
}

bool BubbleTip::eventFilter(QObject* watched, QEvent* event)
{
    if (watched == m_target && (event->type() == QEvent::Move || event->type() == QEvent::Resize)) {
        adjustTipsForTarget(m_target); // 目标移动时立即调整位置
    }
    return QWidget::eventFilter(watched, event);
}

void BubbleTip::showTip(QWidget* target,
                        const QString& text,
                        Position position,
                        int duration,
                        Type type,
                        QWidget* parent)
{
    new BubbleTip(target, text, position, duration, type, parent);
}

void BubbleTip::hideAll()
{
    for (BubbleTip* tip : m_queue) {
        tip->startHideAnimation();
    }
    m_queue.clear();
    m_targetMap.clear();
}
