//
// Created by uos on 2022/4/26.
//

#include "SelectFileItemDelegate.h"
#include"BaseItemDelegate.h"
#include "utils/Utils.h"
#include <DApplication>
#include <DPaletteHelper>
#include <DGuiApplicationHelper>
#include <DPalette>
#include <DStyle>
#include <QAbstractItemView>
#include <QFontMetrics>
#include <QHelpEvent>
#include <QModelIndex>
#include <QPainter>
#include <QStyleOptionViewItem>
#include <QToolTip>

DWIDGET_USE_NAMESPACE

SelectFileItemDelegate::SelectFileItemDelegate(QObject *parent)
        : QItemDelegate(parent)
{
}

void SelectFileItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                             const QModelIndex &index) const
{
    if (!index.isValid()) {
        QItemDelegate::paint(painter, option, index);
        return;
    }

    painter->save();
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setOpacity(1);
    QStyleOptionViewItem opt = option;
    initStyleOption(&opt, index);

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

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

    auto margin = style->pixelMetric(DStyle::PM_ContentsMargins, &option);
    auto iconSize = style->pixelMetric(DStyle::PM_ListViewIconSize, &option);

    auto palette = DGuiApplicationHelper::instance()->applicationPalette();

    QPen forground;
    if (index.data(Qt::UserRole + 2).isValid()) {
        forground.setColor(palette.color(cg, static_cast<DPalette::ColorType>(index.data(Qt::UserRole + 2).toInt())));
    } else {
        forground.setColor(palette.color(cg, DPalette::Text));
    }
    if (opt.state & DStyle::State_Enabled) {
        if (opt.state & DStyle::State_Selected) {
            forground.setColor(palette.color(cg, DPalette::TextLively));
            if (opt.state & DStyle::State_Sunken) {
                auto hlColor = opt.palette.highlight().color();
                hlColor.setAlphaF(.1);
                auto newColor = style->adjustColor(forground.color(), 0, 0, 0, 0, 0, 0, -40);
                forground = style->blendColor(newColor, hlColor);
            } else if (opt.state & DStyle::State_MouseOver) {
                forground = style->adjustColor(forground.color(), 0, 0, 20);
            }
        } else {
            if (opt.state & DStyle::State_MouseOver) {
                auto type = DGuiApplicationHelper::instance()->themeType();
                forground = style->adjustColor(forground.color(), 0, 0, type == DGuiApplicationHelper::DarkType ? 20 : -50);
            }
        }
    }

    QRect rect = opt.rect;
    QFontMetrics fm(opt.font);
    QRect textRect = rect;

    switch (opt.viewItemPosition) {
        case QStyleOptionViewItem::Beginning: {
            rect.setX(rect.x() + margin);  // left margin
        } break;
        case QStyleOptionViewItem::Middle: {
            // whole rect
        } break;
        case QStyleOptionViewItem::End: {
            rect.setWidth(rect.width() - margin);  // right margin
        } break;
        case QStyleOptionViewItem::OnlyOne: {
            rect.setX(rect.x() + margin);
            rect.setWidth(rect.width() - margin);
        } break;
        default: {
            painter->restore();
            QItemDelegate::paint(painter, option, index);
            return;
        }
    }

    QVariant value;
    int dirState = 0;
    QRect checkRect;
    Qt::CheckState checkState = Qt::Unchecked;
    value = index.data(Qt::CheckStateRole);
    if (value.isValid() && index.column() == 0) {
        checkState = static_cast<Qt::CheckState>(value.toInt());
        checkRect = doCheck(opt, opt.rect, value);
        checkRect.setSize(QSize(20, 20));
        dirState = index.data(Qt::UserRole + 10).toInt();
        int checkboxOffset = (dirState == 1 || dirState == 2) ? 0 : 7;  // checkbox offset
   //     qInfo()<<"dirState = "<<dirState<<", checkboxOffset = "<<checkboxOffset;
        checkRect.moveLeft(opt.rect.left() + checkboxOffset);
        if (m_alwaysChecked) {
            checkState = Qt::Checked;
        }
        drawCheck(painter, opt, checkRect, checkState);
    }

    QString text;
    QRect iconRect;
    if (opt.viewItemPosition == QStyleOptionViewItem::Beginning ||
        opt.viewItemPosition == QStyleOptionViewItem::OnlyOne) {
        if (opt.features & QStyleOptionViewItem::HasDecoration) {
            textRect = rect;
            // | margin - icon - spacing - text - margin |
            textRect.setX(textRect.x() + 50);
            textRect.setWidth(textRect.width() - margin);
            text = fm.elidedText(opt.text, opt.textElideMode, textRect.width());

            iconRect = rect;
            int offset = (dirState == 1 || dirState == 2) ? 5 : 15;
            iconRect.setX(rect.x() + margin + offset); // 父节点文件夹与chechbox的偏移量
            iconRect.setWidth(iconSize);
        } else {
            // | margin - text - margin |
            textRect = rect;
            textRect.setX(textRect.x() + 20);
            textRect.setWidth(textRect.width() - margin + 30);
            text = fm.elidedText(opt.text, opt.textElideMode, textRect.width());
        }
    } else {
        // | margin - text - margin |
        textRect = rect;
        textRect.setX(textRect.x() - 2); // type 列内容显示偏移量
        textRect.setWidth(textRect.width() - margin);
        text = fm.elidedText(opt.text, opt.textElideMode, textRect.width());
    }

    if (opt.features & QStyleOptionViewItem::HasDecoration &&
        (opt.viewItemPosition == QStyleOptionViewItem::Beginning ||
         opt.viewItemPosition == QStyleOptionViewItem::OnlyOne)) {
        auto diff = (iconRect.height() - iconSize) / 2;
        opt.icon.paint(painter, iconRect.adjusted(0, diff, 0, -diff));
    }
    painter->setPen(forground);
    int textOffset = (dirState == 1 || dirState == 2) ? -3 : 9; // Name text offset
    textRect.setX(textRect.x() + textOffset);
    painter->drawText(textRect, static_cast<int>(opt.displayAlignment), text);

    painter->restore();
}

//void SelectFileItemDelegate::drawCheck(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect,
//                                 Qt::CheckState state) const
//{
//    QPixmap pixmap;
//    if (state == Qt::Unchecked) {
//        pixmap = Utils::hidpiPixmap(":/resources/icons/UnChecked-Normal-Light.svg", QSize(20, 20));
//    } else if (state == Qt::Checked) {
//        pixmap = Utils::hidpiPixmap(":/resources/icons/Checked-Normal-Light.svg", QSize(20, 20));
//    } else {
//        pixmap = Utils::hidpiPixmap(":/resources/icons/Mixed-Normal-Light.svg", QSize(20, 20));
//    }
//    painter->drawPixmap(rect, pixmap);
//}

QWidget *SelectFileItemDelegate::createEditor(QWidget *, const QStyleOptionViewItem &,
                                        const QModelIndex &) const
{
    return nullptr;
}

QSize SelectFileItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QSize size = QItemDelegate::sizeHint(option, index);
    size.setHeight(std::max(36, size.height()));
    return size;
}

bool SelectFileItemDelegate::helpEvent(QHelpEvent *e, QAbstractItemView *view,
                                 const QStyleOptionViewItem &option, const QModelIndex &index)
{
    if (!e || !view)
        return false;

    if (e->type() == QEvent::ToolTip) {
        QToolTip::hideText();
        QRect rect = view->visualRect(index);
        QRect textRect = rect;

        QStyleOptionViewItem opt = option;
        initStyleOption(&opt, index);

        auto margin = DStyle::pixelMetric(view->style(), DStyle::PM_ContentsMargins);

        // textRect
        if (index.column() == 0) {
            if (opt.features & QStyleOptionViewItem::HasDecoration) {
                textRect.setX(textRect.x());
            } else {
                textRect.setX(textRect.x());
            }
        } else {
            textRect.setX(textRect.x() + margin);
        }

        if (rect.x() + rect.width() >= view->width()) {
            textRect.setWidth(textRect.width());
        } else {
            textRect.setWidth(textRect.width());
        }

        // textWidth
        QFontMetrics fm(opt.font);
        int w = fm.size(Qt::TextSingleLine, opt.text).width();

        if (textRect.width() < w) {
            QVariant tooltip = index.data(Qt::DisplayRole);
            if (tooltip.canConvert<QString>()) {
                QToolTip::showText(e->globalPos(),
                                   QString("<div>%1</div>").arg(tooltip.toString().toHtmlEscaped()),
                                   view);
                return true;
            }
        }
    }
    if (!QItemDelegate::helpEvent(e, view, option, index))
        QToolTip::hideText();

    return false;
}

void SelectFileItemDelegate::initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
{
    option->showDecorationSelected = true;
    bool ok = false;
    if (index.data(Qt::TextAlignmentRole).isValid()) {
        uint value = index.data(Qt::TextAlignmentRole).toUInt(&ok);
        option->displayAlignment = static_cast<Qt::Alignment>(value);
    }
    if (!ok)
        option->displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
    option->textElideMode = Qt::ElideRight;
    option->features = QStyleOptionViewItem::HasDisplay;
    if (index.data(Qt::DisplayRole).isValid())
        option->text = index.data().toString();

    if (index.data(Qt::DecorationRole).isValid()) {
        option->features |= QStyleOptionViewItem::HasDecoration;
        option->icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
    }

    if(option->decorationPosition != QStyleOptionViewItem::Right) {
        option->decorationPosition=QStyleOptionViewItem::Right;
    }
}

void SelectFileItemDelegate::setAlwaysChecked(bool checked)
{
    m_alwaysChecked = checked;
}
