#include "qmtreeview.h"

#include <QPen>
#include <QPainter>
#include <QStyleOptionFrame>
#include <QHeaderView>
#include <QPushButton>
#include <QtEvents>
#include <QMenu>
#include <QMimeData>
// Implementation

#include <QDebug>

#include "treemodel.h"


QMTreeView::QMTreeView(QWidget *parent):
    QTreeView(parent)
{
    header()->setFixedHeight(30);
    QPushButton * cornerbutton = new QPushButton(this);
    setCornerWidget(cornerbutton);
    connect(cornerbutton, &QPushButton::released, this, &QMTreeView::onCornerButtonRelease);

    setLineWidth(1);
    setAlternatingRowColors(false);

    setAcceptDrops(true);  // Habilita el drop
    setDropIndicatorShown(true);
    setTreePosition(0);

    return;
    setStyleSheet("QHeaderView::section:horizontal {"
                        "background-color: qlineargradient(spread:reflect,"
                        "x1:0, y1:0, x2:0, y2:1,"
                        "stop:0 rgba(255, 255, 255, 255),"
                        "stop:1 rgba(164, 164, 164, 255));"
                        "border: 1px solid rgb(153, 153, 153);"
                        "border-width: 0 1px 1px 0;"
                        "}"
                        "QTreeView::item {"
                        "border-bottom: 0.5px solid lightgray;"
                        "selection-color: black;"
                        "}"
                        "QTreeView::item:selected { /*被选中的index*/"
                        "background: qlineargradient("
                        "x1: 0, y1: 0, x2: 0, y2: 1,"
                        "stop: 0 #FAFBFE,"
                        "stop: 1 #DCDEF1);"
                        "}"
                        "QTreeView::branch {"
                        "background: yellow;"
                        "}"
                        "QTreeView::branch:has-siblings:!adjoins-item {"
                        "background: cyan;"
                        "}"
                        "QTreeView::branch:has-siblings:adjoins-item {"
                        "background: red;"
                        "}"
                        "QTreeView::branch:!has-children:!has-siblings:adjoins-item {"
                        "background: blue;"
                        "}"
                        "QTreeView::branch:closed:has-children:has-siblings {"
                        "background: black;"
                        "}"
                        "QTreeView::branch:has-children:!has-siblings:closed {"
                        "background: gray;"
                        "}"
                        "QTreeView::branch:open:has-children:has-siblings {"
                        "background: magenta;"
                        "}"
                        "QTreeView::branch:open:has-children:!has-siblings {"
                        "background: green;}");
}

void QMTreeView::resizeEvent(QResizeEvent *event)
{
    QTreeView::resizeEvent(event);
}


/*
void QMTreeView::drawTree(QPainter *painter, const QRegion &region) const
{
    QTreeView::drawTree(painter, region);
    return;

    if (model() && model()->rowCount() > 0)
    {
        QTreeView::drawTree(painter, region);
    }
    else
    {
        // If no items draw a text in the center of the viewport.
        QPainter painter(viewport());
        QString text(tr("There are no elements in this view"));
        QRect textRect = painter.fontMetrics().boundingRect(text);
        textRect.moveCenter(viewport()->rect().center());
        painter.drawText(textRect, Qt::AlignCenter, text);
    }

*/
    /*
    Q_D(const QTreeView);
    const QVector<QTreeViewItem> viewItems = d->viewItems;

    QStyleOptionViewItem option = d->viewOptionsV1();
    const QStyle::State state = option.state;
    d->current = 0;

    if (viewItems.count() == 0 || d->header->count() == 0 || !d->itemDelegate) {
        d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
        return;
    }

    int firstVisibleItemOffset = 0;
    const int firstVisibleItem = d->firstVisibleItem(&firstVisibleItemOffset);
    if (firstVisibleItem < 0) {
        d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
        return;
    }

    const int viewportWidth = d->viewport->width();

    QPoint hoverPos = d->viewport->mapFromGlobal(QCursor::pos());
    d->hoverBranch = d->itemDecorationAt(hoverPos);

    QVector<int> drawn;
    bool multipleRects = (region.rectCount() > 1);
    for (const QRect &a : region) {
        const QRect area = (multipleRects
                            ? QRect(0, a.y(), viewportWidth, a.height())
                            : a);
        d->leftAndRight = d->startAndEndColumns(area);

        int i = firstVisibleItem; // the first item at the top of the viewport
        int y = firstVisibleItemOffset; // we may only see part of the first item

        // start at the top of the viewport  and iterate down to the update area
        for (; i < viewItems.count(); ++i) {
            const int itemHeight = d->itemHeight(i);
            if (y + itemHeight > area.top())
                break;
            y += itemHeight;
        }

        // paint the visible rows
        for (; i < viewItems.count() && y <= area.bottom(); ++i) {
            const int itemHeight = d->itemHeight(i);
            option.rect.setRect(0, y, viewportWidth, itemHeight);
            option.state = state | (viewItems.at(i).expanded ? QStyle::State_Open : QStyle::State_None)
                                 | (viewItems.at(i).hasChildren ? QStyle::State_Children : QStyle::State_None)
                                 | (viewItems.at(i).hasMoreSiblings ? QStyle::State_Sibling : QStyle::State_None);
            d->current = i;
            d->spanning = viewItems.at(i).spanning;
            if (!multipleRects || !drawn.contains(i)) {
                drawRow(painter, option, viewItems.at(i).index);
                if (multipleRects)   // even if the rect only intersects the item,
                    drawn.append(i); // the entire item will be painted
            }
            y += itemHeight;
        }

        if (y <= area.bottom()) {
            d->current = i;
            d->paintAlternatingRowColors(painter, &option, y, area.bottom());
        }
    }
    */
//}

void QMTreeView::drawRow(QPainter * painter, const QStyleOptionViewItem & options, const QModelIndex & index) const
{
    QTreeView::drawRow(painter, options, index);
    //return;

    int m_iWidth = 1;
    QColor m_gridLineColor = QColor(200, 200, 200);

    QPen pen;
    pen.setWidth(m_iWidth);
    pen.setColor(m_gridLineColor);

    QBrush brush;
    brush.setColor(QColor(0,0,0,0));

    painter->save();
    painter->setPen(pen);
    painter->setBrush(brush);
    painter->drawRect(options.rect);
    painter->restore();
}

void QMTreeView::drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const
{
    if (!index.isValid()) {
        QTreeView::drawBranches(painter, rect, index);
        return;
    }

    // Calcula el ancho del branch basado en el nivel de profundidad
    int depth = 0;
    QModelIndex parentIndex = index.parent();
    while (parentIndex.isValid()) {
        ++depth;
        parentIndex = parentIndex.parent();
    }

    // Calcula el ancho del branch
    int branchWidth = depth * indentation();

    // Dibuja el rectángulo del branch
    QRect branchRect(rect.left(), rect.top(), branchWidth, rect.height());
    painter->save();
    painter->setBrush(Qt::yellow);  // Cambia el color según prefieras
    painter->setPen(Qt::NoPen);    // Sin bordes
    painter->drawRect(branchRect);
    painter->restore();

    // Llama al método base para que Qt dibuje el resto
    QTreeView::drawBranches(painter, rect, index);
    return;


    QTreeView::drawBranches(painter, rect, index);
    //return;

    //int m_iWidth = 1;
    QColor m_gridLineColor = QColor(200, 200, 200);

    QPen pen;
    //pen.setWidth(m_iWidth);
    pen.setColor(m_gridLineColor);

    QBrush brush;
    brush.setColor(QColor(0,0,0,0));

    //painter->save();
    painter->setPen(pen);
    painter->setBrush(brush);
    painter->drawRect(rect);
    //painter->restore();

    //const QTreeViewItem &viewItem = d->viewItems.at(item);
    //int level = viewItem.level;


    //Q_Q(const QMTreeView);
    /*
    const bool reverse = isRightToLeft();
    const int indent = d->indent;
    const int outer = d->rootDecoration ? 0 : 1;
    const int item = d->current;
    const QTreeViewItem &viewItem = d->viewItems.at(item);
    int level = viewItem.level;
    QRect primitive(reverse ? rect.left() : rect.right() + 1, rect.top(), indent, rect.height());

    QModelIndex parent = index.parent();
    QModelIndex current = parent;
    QModelIndex ancestor = current.parent();

    QStyleOptionViewItem opt = viewOptions();
    QStyle::State extraFlags = QStyle::State_None;
    if (isEnabled())
        extraFlags |= QStyle::State_Enabled;
    if (hasFocus())
        extraFlags |= QStyle::State_Active;
    QPoint oldBO = painter->brushOrigin();
    if (verticalScrollMode() == QAbstractItemView::ScrollPerPixel)
        painter->setBrushOrigin(QPoint(0, verticalOffset()));

    if (d->alternatingColors) {
        opt.features.setFlag(QStyleOptionViewItem::Alternate, d->current & 1);
    }

    // When hovering over a row, pass State_Hover for painting the branch
    // indicators if it has the decoration (aka branch) selected.
    bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
                    && opt.showDecorationSelected
                    && index.parent() == d->hover.parent()
                    && index.row() == d->hover.row();

    if (d->selectionModel->isSelected(index))
        extraFlags |= QStyle::State_Selected;

    if (level >= outer) {
        // start with the innermost branch
        primitive.moveLeft(reverse ? primitive.left() : primitive.left() - indent);
        opt.rect = primitive;

        const bool expanded = viewItem.expanded;
        const bool children = viewItem.hasChildren;
        bool moreSiblings = viewItem.hasMoreSiblings;

        opt.state = QStyle::State_Item | extraFlags
                    | (moreSiblings ? QStyle::State_Sibling : QStyle::State_None)
                    | (children ? QStyle::State_Children : QStyle::State_None)
                    | (expanded ? QStyle::State_Open : QStyle::State_None);
        opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch);

        style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
    }
    // then go out level by level
    for (--level; level >= outer; --level) { // we have already drawn the innermost branch
        primitive.moveLeft(reverse ? primitive.left() + indent : primitive.left() - indent);
        opt.rect = primitive;
        opt.state = extraFlags;
        bool moreSiblings = false;
        if (d->hiddenIndexes.isEmpty()) {
            moreSiblings = (d->model->rowCount(ancestor) - 1 > current.row());
        } else {
            int successor = item + viewItem.total + 1;
            while (successor < d->viewItems.size()
                   && d->viewItems.at(successor).level >= uint(level)) {
                const QTreeViewItem &successorItem = d->viewItems.at(successor);
                if (successorItem.level == uint(level)) {
                    moreSiblings = true;
                    break;
                }
                successor += successorItem.total + 1;
            }
        }
        if (moreSiblings)
            opt.state |= QStyle::State_Sibling;
        opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch);

        style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
        current = ancestor;
        ancestor = current.parent();
    }
    painter->setBrushOrigin(oldBO);*/
}

/*
int indexRowSizeHint(const QModelIndex &index)
{

}

int rowHeight(const QModelIndex &index)
{

}
*/

void QMTreeView::keyPressEvent(QKeyEvent *e)
{
    bool bNextCellOnEnter = true;
    bool bNextRowOnLastCol = true;
/*
        Key_Left = 0x01000012,
        Key_Up = 0x01000013,
        Key_Right = 0x01000014,
        Key_Down = 0x01000015,
*/
    if(bNextCellOnEnter && (e->key() == Qt::Key_Return | e->key() == Qt::Key_Enter | e->key() == Qt::Key_Right))
    {
        qint32  cr = currentIndex().row(),
                cc = currentIndex().column(),
                c  = model()->columnCount();

        QHeaderView *hdr = static_cast<QHeaderView*>(header());

        if(hdr)
           cc = hdr->visualIndex(cc);

        if(cc + 1 < c)
        {
            moveTo(cr, cc + 1);

            if(editTriggers() == QAbstractItemView::AllEditTriggers)
                edit(currentIndex());
        }
        else if(bNextRowOnLastCol)
        {
            // TODO: comporbar si tiene hijos y si tiene mover el selector a este.

            if(cr < model()->rowCount() - 1)
                moveTo(cr + 1, 0);
            if(editTriggers() == QAbstractItemView::AllEditTriggers)
                edit(currentIndex());
        }
        else
           QTreeView::keyPressEvent(e);
    }
    else if(e->key() == Qt::Key_Left /*&& currentIndex().row() == model()->rowCount() - 1*/)
    {
        qint32  cr = currentIndex().row(),
                cc = currentIndex().column(),
                c  = model()->columnCount();

        QHeaderView *hdr = static_cast<QHeaderView*>(header());

        if(hdr)
           cc = hdr->visualIndex(cc);

        if(cc - 1 > -1)
        {
            moveTo(cr, cc - 1);

            if(editTriggers() == QAbstractItemView::AllEditTriggers)
                edit(currentIndex());
        }
        /*
        else if(bNextRowOnLastCol)
        {
            // TODO: comporbar si tiene hijos y si tiene mover el selector a este.

            if(cr < model()->rowCount() - 1)
                moveTo(cr + 1, 0);
            if(editTriggers() == QAbstractItemView::AllEditTriggers)
                edit(currentIndex());
        }
        */
        else
           QTreeView::keyPressEvent(e);
    }
    /*
    else if(e->key() == Qt::Key_Up)
    {
        qint32  cr = currentIndex().row(),
                cc = currentIndex().column(),
                c  = model()->columnCount();

        if(cr > 0)
            moveTo(cr - 1, currentIndex().column());
    }
    */
    else if(e->key() == Qt::Key_Down && currentIndex().row() == model()->rowCount() - 1)
    {
        addNewRecord(currentIndex());

        //QTreeView::keyPressEvent(e); // quitar esto
    }
    /*
    else if(e->key() == Qt::Key_Down)
    {
        qint32  cr = currentIndex().row(),
                cc = currentIndex().column(),
                c  = model()->columnCount();

        if(cr < model()->rowCount() - 1)
            moveTo(cr + 1, currentIndex().column());
    }
    */
    else
    {
        QModelIndex c(currentIndex());

        QTreeView::keyPressEvent(e);

        if(c.row() != currentIndex().row() || c.column() != currentIndex().column())
        {
            selectionModel()->select(currentIndex(), QItemSelectionModel::Select);
            selectionModel()->select(c, QItemSelectionModel::Deselect);
        }
    }
}

void QMTreeView::moveTo(int r, int c)
{
    QHeaderView *hdr = static_cast<QHeaderView*>(header());
    if(!hdr)
        return;

    if(c > hdr->count() - 1)
        c = hdr->count() - 1;

    if(r > model()->rowCount() - 1)
        r = model()->rowCount() - 1;

    c = nextVisibleIndex(hdr->logicalIndex(c));

    QModelIndex oi = currentIndex(),
                ix = model()->index(r, c, oi.parent().isValid() ? oi.parent() : QModelIndex());

    qDebug() << "Pos" << r << ":" << c << "MoveTo" << ix << "IsValid ?" << ix.isValid();
    if(ix.isValid())
    {
        QItemSelection os(currentIndex(), currentIndex());

        setCurrentIndex(ix);
        selectionModel()->setCurrentIndex(ix, QItemSelectionModel::ClearAndSelect);

        QItemSelection ns(currentIndex(), currentIndex());

        QTreeView::selectionChanged(os, ns);

        qDebug() << "MOveTo" << currentIndex();
        //emit onPositionChanged(currentRow(), currentColumn());
    }
}

int QMTreeView::nextVisibleIndex(int c)
{
    QHeaderView *hdr = static_cast<QHeaderView*>(header());
    if(!hdr)
        return c;

    if(c > hdr->count() - 1)
        return nextVisibleIndex(hdr->count() - 1);

    for(int i = c; i < hdr->count() - 1; i++)
    {
        if(!hdr->isSectionHidden(i))
                return i;
    }
    return c;
}

bool QMTreeView::addNewRecord(const QModelIndex &index)
{
    if(editTriggers() == QAbstractItemView::NoEditTriggers) // read Only
        return false;

    insertRow();
    scrollToBottom();
    moveTo(model()->rowCount(), nextVisibleIndex(0));

    /*
    if(!bCanAddRow)
        return false;

    if(model() && model()->inherits("PBSDataModel"))
    {
        PBSDataModel *pModel = static_cast<PBSDataModel*>(model());
        if(pModel)
        {
            int r = currentIndex().row(),
                c = currentIndex().column();

            if(!pModel->haveEmptyRow())
            {
                pModel->insertEmptyRow();
                emit newRecordAdd();

                resizeRowToContents(pModel->rowCount());
                scrollToBottom();

                if(bGotoFirstCellOnNewRec)
                    c = nextVisibleIndex(0);
                moveTo(pModel->rowCount(), c);

                emit newRecordAdd();
            }
        }
    }
    else
    {
        model()->insertRow(model()->rowCount(QModelIndex()));
        model()->submit();
    }
    */
    return true;
}

void QMTreeView::insertChild()
{
    QModelIndex selindex = selectionModel()->currentIndex();
    QAbstractItemModel *treemodel = model();

    if (treemodel->columnCount(selindex) == 0)
    {
        if (!treemodel->insertColumn(0, selindex))
            return;
    }

    if (!treemodel->insertRow(0, treemodel->index(selindex.row(), 0, selindex.parent())))
        return;

    /*
    for (int column = 0; column < treemodel->columnCount(selindex); ++column)
    {
        QModelIndex child = treemodel->index(0, column, selindex);
        treemodel->setData(child, QVariant(""), Qt::EditRole);
        if (!treemodel->headerData(column, Qt::Horizontal).isValid())
            treemodel->setHeaderData(column, Qt::Horizontal, QVariant("[No header]"), Qt::EditRole);
    }
    */

    selectionModel()->setCurrentIndex(treemodel->index(0, 0, selindex),
                                            QItemSelectionModel::ClearAndSelect);
}

void QMTreeView::addRow()
{
    //QModelIndex selindex = selectionModel()->currentIndex();
    QAbstractItemModel *treemodel = model();

    if (!treemodel->insertRow(treemodel->rowCount()))
        return;
}

void QMTreeView::insertRow()
{
    QModelIndex selindex = selectionModel()->currentIndex();
    QAbstractItemModel *treemodel = model();

    //int i = 1;
    //setFirstColumnSpanned(i, model()->index(i, 0), true);

    if (!treemodel->insertRow(selindex.row() + 1, selindex.parent()))
        return;
}

void QMTreeView::removeRow()
{
    QModelIndex selindex = selectionModel()->currentIndex();
    QAbstractItemModel *treemodel = model();
    treemodel->removeRow(selindex.row(), selindex.parent());
}

void QMTreeView::onCornerButtonRelease()
{
    QMenu *menu = new QMenu();
    menu->addAction(new QAction("javi"));
    menu->exec();

    //QPushButton *bt = static_cast<QPushButton *>(cornerWidget());
    //bt->setMenu(menu);
}


void QMTreeView::dragEnterEvent(QDragEnterEvent *event) {
    if (event->mimeData()->hasText()) {
        event->acceptProposedAction();
    }
}

void QMTreeView::dragMoveEvent(QDragMoveEvent *event) {
    if (event->mimeData()->hasText()) {
        event->acceptProposedAction();
    }
}

void QMTreeView::dropEvent(QDropEvent *event) {
    if (event->mimeData()->hasText()) {
        QString data = event->mimeData()->text();
        QStringList items = data.split("\n");

        // Aquí puedes insertar los datos en el modelo del QTreeView
        QAbstractItemModel *treeModel = model();
        for (const QString &item : items) {
            if (!item.isEmpty()) {
                QModelIndex parentIndex = currentIndex();
                treeModel->insertRow(treeModel->rowCount(parentIndex), parentIndex);
                QModelIndex newItemIndex = treeModel->index(treeModel->rowCount(parentIndex) - 1, 0, parentIndex);
                treeModel->setData(newItemIndex, item);
            }
        }

        event->acceptProposedAction();
    }
}
