#include <QPaintEvent>
#include <QPainter>
#include <QPainterPath>
#include <QScroller>
#include <DApplication>
#include <DGuiApplicationHelper>
#include <DPalette>
#include <DStyle>
#include <DStyleHelper>

#include "utils/Utils.h"
#include "ImmuBaseTableView.h"

#if DTK_VERSION >= DTK_VERSION_CHECK(5, 5, 10, 0)
    #include <DPaletteHelper>
#else
    #include <DApplicationHelper>
#endif

static const int kSpacingMargin = 4;
static const QSize kDropDownSize {11, 10};


ImmuBaseHeaderView::ImmuBaseHeaderView(Qt::Orientation orientation, QWidget *parent)
    : BaseHeaderView(orientation, parent)
{
    installEventFilter(this);
    viewport()->setAutoFillBackground(false);
}

void ImmuBaseHeaderView::paintEvent(QPaintEvent *event)
{
    QPainter painter(viewport());
    painter.save();
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
    painter.setClipping(true);

    // 绘制白色背景和灰色边框，顶部圆角，底部直角，且不绘制底部横线
    QBrush bgBrush(Qt::white);
    if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) {
        bgBrush.setColor(QColor(255, 255, 255));
    } else {
        bgBrush.setColor(QColor(40, 40, 40));
    }
    QRect rect = viewport()->rect();
    int radius = 8;
    QPainterPath path;
    // 顶部左圆角
    path.moveTo(rect.left() + radius, rect.top());
    path.arcTo(QRect(rect.left(), rect.top(), 2 * radius, 2 * radius), 90, 90);
    // 左边
    path.lineTo(rect.left(), rect.bottom());
    // 右边
    path.lineTo(rect.right(), rect.bottom());
    // 右上圆角
    path.lineTo(rect.right(), rect.top() + radius);
    path.arcTo(QRect(rect.right() - 2 * radius, rect.top(), 2 * radius, 2 * radius), 0, 90);
    path.closeSubpath();
    painter.fillPath(path, bgBrush);
    QPen borderPen(QColor(250, 250, 250));
    if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) {
        borderPen.setColor(QColor(250, 250, 250));
    } else {
        borderPen.setColor(QColor(16, 16, 16));
    }
    borderPen.setWidth(1);
    painter.setPen(borderPen);
    // 只绘制左、右、上边框（不绘制底部横线）
    QPainterPath borderPath;
    // 顶部左圆角
    borderPath.moveTo(rect.left() + radius, rect.top());
    borderPath.arcTo(QRect(rect.left(), rect.top(), 2 * radius, 2 * radius), 90, 90);
    // 左边
    borderPath.lineTo(rect.left(), rect.bottom());
    // 右边
    borderPath.moveTo(rect.right(), rect.bottom());
    borderPath.lineTo(rect.right(), rect.top() + radius);
    // 顶部右圆角
    borderPath.arcTo(QRect(rect.right() - 2 * radius, rect.top(), 2 * radius, 2 * radius), 0, 90);
    // 顶部横线
    borderPath.lineTo(rect.left() + radius, rect.top());
    painter.drawPath(borderPath);

    painter.restore();
    DHeaderView::paintEvent(event);
}

void ImmuBaseHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setOpacity(1);

    DPalette::ColorGroup cg;
    QStyleOption opt;
    opt.initFrom(this);
    if (!(opt.state & DStyle::State_Enabled)) {
        cg = DPalette::Disabled;
    } else {
        cg = DPalette::Active;
    }

#if DTK_VERSION >= DTK_VERSION_CHECK(5, 5, 10, 0)
    DPaletteHelper *dAppHelper = DPaletteHelper::instance();
#else
    DApplicationHelper *dAppHelper = DApplicationHelper::instance();
#endif
    DPalette palette = dAppHelper->palette(this);

    DStyle *style = dynamic_cast<DStyle *>(DApplication::style());

    QStyleOptionHeader option;
    initStyleOption(&option);
    int margin = style->pixelMetric(DStyle::PM_ContentsMargins, &option);

    // title
    QRect contentRect(rect.x(), rect.y(), rect.width(), rect.height() - m_spacing);
    QRect hSpacingRect(rect.x(), contentRect.height(), rect.width(),
                       rect.height() - contentRect.height());

    QBrush contentBrush(palette.color(cg, DPalette::Base));

    // 去除表头分隔线，不再绘制vSpacingRect和hSpacingRect
    QBrush vSpacingBrush(palette.color(cg, DPalette::FrameBorder));
    QRectF vSpacingRect(rect.x(), rect.y() + kSpacingMargin, m_spacing, rect.height() - kSpacingMargin * 2);
    QBrush clearBrush(palette.color(cg, DPalette::Window));

    if (visualIndex(logicalIndex) > 1) {
        painter->fillRect(vSpacingRect, clearBrush);
        painter->fillRect(vSpacingRect, vSpacingBrush);
    }

    QPen foreground;
    auto type = DGuiApplicationHelper::instance()->themeType();
    foreground.setColor(palette.color(cg, DPalette::Text));
    if (opt.state == QStyle::State_Enabled && m_pressed == logicalIndex) {
        foreground = opt.palette.highlight().color();
    } else if (opt.state == QStyle::State_Enabled && m_hover == logicalIndex) {
        foreground = style->adjustColor(foreground.color(), 0, 0, type == DGuiApplicationHelper::DarkType ? 20 : -50);
    }

    QRect textRect;
    if (sortIndicatorSection() == logicalIndex) {
        textRect = {
            contentRect.x() + margin,
            contentRect.y(),
            contentRect.width() - margin * 3 - kDropDownSize.width(),
            contentRect.height()};
    } else {
        textRect = {
            contentRect.x() + margin,
            contentRect.y(),
            contentRect.width() - margin,
            contentRect.height()};
    }
    QString title = model()->headerData(logicalIndex, orientation(), Qt::DisplayRole).toString();
    int align = model()->headerData(logicalIndex, orientation(), Qt::TextAlignmentRole).toInt();
    // foreground
    painter->setPen(foreground);
    QString objName = model()->objectName();
    if (0 == logicalIndex && objName == "ID_UserDataBackupSelectWidget") { // 绘制全选checkbox
        const int checkboxWidth = 20;
        const int checkboxHight = 20;
        const int xOffset = 10;
        const int yOffset = 10;
        static QPixmap uncheckedNormalLightPix = Utils::hidpiPixmap(":/resources/icons/UnChecked-Normal-Light.svg", QSize(checkboxWidth, checkboxHight));
        static QPixmap checkedNormalLightPix = Utils::hidpiPixmap(":/resources/icons/Checked-Normal-Light.svg", QSize(checkboxWidth, checkboxHight));
        static QPixmap mixCheckedNormalLightPix = Utils::hidpiPixmap(":/resources/icons/Mixed-Normal-Light.svg", QSize(checkboxWidth, checkboxHight));
        int x = textRect.x() + xOffset;
        if (m_checkAll == Qt::Checked) {
            painter->drawPixmap(x, textRect.y() + yOffset, checkboxWidth, checkboxHight, checkedNormalLightPix);
        } else if (m_checkAll == Qt::PartiallyChecked){
            painter->drawPixmap(x, textRect.y() + yOffset, checkboxWidth, checkboxHight, mixCheckedNormalLightPix);
        } else {
            painter->drawPixmap(x, textRect.y() + yOffset, checkboxWidth, checkboxHight, uncheckedNormalLightPix);
        }
        painter->drawText(textRect.x() + 35, textRect.y() + 25, title); // 调整 Name 的偏移量
    } else {
        if (1 == logicalIndex && objName == "ID_UserDataBackupSelectWidget") {
            textRect.setX(textRect.x() - 5);
            textRect.setY(textRect.y() + 5);
            painter->drawText(textRect, align, title);
        } else {
            painter->drawText(textRect, align, title);
        }
    }

    // sort indicator
    if (isSortIndicatorShown() && logicalIndex == sortIndicatorSection()) {
        QRect sortIndicator(textRect.x() + textRect.width() + margin,
                            textRect.y() + qCeil((textRect.height() - kDropDownSize.height()) / 2.),
                            kDropDownSize.width(), kDropDownSize.height());
        option.rect = sortIndicator;
        if (sortIndicatorOrder() == Qt::DescendingOrder) {
            style->drawPrimitive(DStyle::PE_IndicatorArrowDown, &option, painter, this);
        } else if (sortIndicatorOrder() == Qt::AscendingOrder) {
            style->drawPrimitive(DStyle::PE_IndicatorArrowUp, &option, painter, this);
        }
    }

    painter->restore();
}

ImmuBaseTableView::ImmuBaseTableView(DWidget *parent)
        : BaseTableView(parent)
{
    m_headerView = new ImmuBaseHeaderView(Qt::Horizontal, this);
    setHeader(m_headerView);
    m_headerView->setSectionsClickable(true);
    m_headerView->setStretchLastSection(true);
    m_headerView->setSortIndicatorShown(true);
    m_headerView->setDefaultAlignment(Qt::AlignLeft);
    m_headerView->setContextMenuPolicy(Qt::CustomContextMenu);
    m_headerView->setFocusPolicy(Qt::TabFocus);

    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setRootIsDecorated(false);
    setItemsExpandable(false);
    setFrameStyle(QFrame::NoFrame);
    viewport()->setAutoFillBackground(false);
    // if set to true, qt will draw item background for you, thats not what you want here!
    setAlternatingRowColors(false);
    setAllColumnsShowFocus(false);
    setFocusPolicy(Qt::TabFocus);
    setSelectionMode(QAbstractItemView::NoSelection);
    setTabOrder(m_headerView, this);

    // add treeview touch scroll support
    QScroller::grabGesture(viewport(), QScroller::TouchGesture);
    connect(m_headerView, &ImmuBaseHeaderView::checkAllChanged, [=] (Qt::CheckState checkState) {
        Q_EMIT checkAllChanged(checkState);
    });
}

void ImmuBaseTableView::paintEvent(QPaintEvent *event)
{
    QPainter painter(viewport());
    painter.save();
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
    painter.setClipping(true);

    // 绘制白色背景和灰色边框，底部圆角，顶部直角
    QBrush bgBrush(Qt::white);
    if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) {
        bgBrush.setColor(QColor(255, 255, 255));
    } else {
        bgBrush.setColor(QColor(40, 40, 40));
    }
    QRect rect = viewport()->rect();
    int radius = 8;
    QPainterPath path;
    // 顶部直角
    path.moveTo(rect.left(), rect.top());
    path.lineTo(rect.right(), rect.top());
    // 右边
    path.lineTo(rect.right(), rect.bottom() - radius);
    // 右下圆角
    path.arcTo(QRect(rect.right() - 2 * radius, rect.bottom() - 2 * radius, 2 * radius, 2 * radius), 0, -90);
    // 底边
    path.lineTo(rect.left() + radius, rect.bottom());
    // 左下圆角
    path.arcTo(QRect(rect.left(), rect.bottom() - 2 * radius, 2 * radius, 2 * radius), 270, -90);
    // 左边
    path.lineTo(rect.left(), rect.top());
    path.closeSubpath();
    painter.fillPath(path, bgBrush);
    QPen borderPen(QColor(250, 250, 250));
    if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) {
        borderPen.setColor(QColor(250, 250, 250));
    } else {
        borderPen.setColor(QColor(16, 16, 16));
    }
    borderPen.setWidth(1);
    painter.setPen(borderPen);
    painter.drawPath(path);

    painter.restore();
    DTreeView::paintEvent(event);
}