#include "MatrixTableWidget.h"
#include "MatrixTableItemDelegate.h"
#include "algorithm/ConsistencyCheck.h"

#include <QApplication>
#include <QDebug>
#include <QDesktopWidget>
#include <QHeaderView>
#include <QMessageBox>
#include <QTimer>
#include <QtMath>

#include "dbService/ClassSet.h"
#include "dbService/DBServiceSet.h"
#include "dbService/NodeMatrixService.h"
#include "dbService/DemandWeightService.h"

MatrixTableWidget::MatrixTableWidget(bool diagonalOne, QWidget *parent) : QTableView(parent), diagonalIsOne(diagonalOne)
{
    model = new QStandardItemModel();
    this->setModel(model);
    paintDone = false;

    //    connect(model, &QStandardItemModel::itemChanged, this,
    //    &MatrixTableWidget::nodeValueChanged);

    connect(this, &QTableView::clicked, this, &MatrixTableWidget::itemClicked);
}

MatrixTableWidget::~MatrixTableWidget() { }

void MatrixTableWidget::addRowNode(QString node, QString name, QString remark)
{
    matrixRows << MatrixTableWidget::MatrixNode(node, name, remark);
}

void MatrixTableWidget::addColNode(QString node, QString name, QString remark)
{
    matrixCols << MatrixTableWidget::MatrixNode(node, name, remark);
}
void MatrixTableWidget::setCurrentPage(int page)
{
    currentPage = page;
}

void MatrixTableWidget::setTableIndexAndTableMsg(int index, int engineerId, int expertId, QString tableMsg)
{
    m_tableIndex = index;
    m_engineerId = engineerId;
    m_expertId   = expertId;
    m_table_msg  = tableMsg;
}

void MatrixTableWidget::setMsgName(QString msgName)
{
    m_msg_name = msgName;
}
QList<MatrixDataSource> MatrixTableWidget::getSource() const
{
    return dataSource;
}

void MatrixTableWidget::paintMatrixTable(QList<NodeMatrixInfo *> nodeValueInfoList)
{
    // qDebug() << "nodeValueInfoList========" << nodeValueInfoList.size();
    int row = matrixRows.count();
    int col = matrixCols.count();
    // qDebug() << row << col;
    this->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    this->setSelectionMode(QAbstractItemView::SingleSelection);
    this->setSelectionBehavior(QAbstractItemView::SelectItems);

    model->setHorizontalHeaderItem(0, new QStandardItem(""));
    for (int c = 0; c < col; ++c) {
        model->setHorizontalHeaderItem(c + 1, new QStandardItem(matrixCols[c].name));
        model->horizontalHeaderItem(c + 1)->setToolTip(matrixCols[c].remark);
    }
    for (int r = 0; r < row; ++r) {
        model->setItem(r, 0, new QStandardItem(matrixRows[r].name));
        model->item(r, 0)->setToolTip(matrixRows[r].remark);
        model->item(r, 0)->setTextAlignment(Qt::AlignCenter);
        model->item(r, 0)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
        for (int c = 1; c < col + 1; ++c) {
            MatrixDataSource data;
            data.row = r;
            data.col = c;
            if (c - 1 == r) {
                if (diagonalIsOne) {
                    data.changed   = true;
                    data.nodeValue = "1";
                } else {
                    data.changed = false;
                    for (NodeMatrixInfo *nodeMatrixInfo : nodeValueInfoList) {
                        if (nodeMatrixInfo->abscissa == matrixRows[r].name
                            && nodeMatrixInfo->ordinate == matrixCols[c - 1].name) {
                            data.nodeValue = nodeMatrixInfo->nodeValue;
                            data.changed   = true;
                        }
                    }
                    // data.nodeValue = "";
                }
            } else {
                data.changed = false;
                // data.nodeValue = "";
                for (NodeMatrixInfo *nodeMatrixInfo : nodeValueInfoList) {
                    if (nodeMatrixInfo->abscissa == matrixRows[r].name
                        && nodeMatrixInfo->ordinate == matrixCols[c - 1].name) {
                        data.nodeValue = nodeMatrixInfo->nodeValue;
                        data.changed   = true;
                    }
                }
            }
            //            data.nodeValue = QString("%1, %2").arg(r).arg(c);
            model->setItem(r, c, new QStandardItem(data.nodeValue));
            model->item(r, c)->setTextAlignment(Qt::AlignCenter);
            if ((r + 1 >= c) && diagonalIsOne) {
                model->item(r, c)->setFlags(Qt::ItemIsEnabled);
                model->item(r, c)->setBackground(QBrush(QColor("lightgray")));
            }
            if (diagonalIsOne) {
                data.node = matrixRows[r].node;
            } else {
                data.node = matrixCols[c - 1].node;
            }
            data.abscissa = matrixRows[r].name;
            data.ordinate = matrixCols[c - 1].name;

            dataSource << data;
        }
    }
    emit returnModel(model);
    emit returnModelName(m_msg_name);
    paintDone = true;
}

void MatrixTableWidget::nodeValueChanged(QStandardItem *item)
{
    if (paintDone) {
        bool valid         = false;
        QStringList valist = item->text().trimmed().split("/");
        if (valist.count() > 2) {  // 两个除号
            valid = false;
            item->setText("");
        } else if (valist.count() == 2) {
            bool num = false;  // 分子
            bool den = false;  // 分母
            valist[0].toDouble(&num);
            valist[1].toDouble(&den);
            if ((!num) || (!den)) {
                valid = false;
                item->setText("");
            }
        } else {
            bool dou = false;  // double
            item->text().trimmed().toDouble(&dou);
            if (!dou) {
                valid = false;
                item->setText("");
            }
        }
        if (diagonalIsOne) {
            if (item->row() + 1 < item->column()) {
                QString newText;
                QStringList split = item->text().split("/");
                if (split.count() == 1) {
                    if (split[0].toDouble() == 1.) {
                        newText = split[0];
                    } else {
                        newText = QString("1/%1").arg(item->text());
                    }
                } else {
                    if (split[0].toDouble() == 1.) {
                        newText = split[1];
                    } else {
                        newText = split[1] + "/" + split[0];
                    }
                }

                model->item(item->column() - 1, item->row() + 1)->setText(newText);
            }
        }
        bool inputDone = true;
        for (int i = 0; i < dataSource.count(); ++i) {
            if (dataSource[i].row == item->row() && dataSource[i].col == item->column()) {
                dataSource[i].nodeValue = item->text().trimmed();
                if (!item->text().trimmed().isEmpty()) {
                    dataSource[i].changed = true;
                } else {
                    dataSource[i].changed = false;
                }
            }

            if (!dataSource[i].changed) {
                inputDone = false;
            }
        }
        //        if (inputDone) { qDebug() << "done"; }
        emit dataReady(inputDone);
    }
}

void MatrixTableWidget::itemClicked(const QModelIndex &index)
{
    if (index.row() + 1 >= index.column()) {
        return;
    }

    QStringList l = { "1/9", "1/7", "1/5", "1/3", "1", "3", "5", "7", "9" };

    SchemeBar *scheme =
            new SchemeBar(model->item(index.row(), 0)->text(), model->horizontalHeaderItem(index.column())->text(), l);
    scheme->setModal(true);
    scheme->setAttribute(Qt::WA_DeleteOnClose);

    connect(scheme, &SchemeBar::setValue, [=](QString val) { editItemData(index, val); });

    scheme->show();
    QPoint p = QCursor::pos();
    if (p.x() + scheme->width() + 10 >= QApplication::desktop()->width()) {
        p.setX(QApplication::desktop()->width() - 10 - scheme->width());
    }
    scheme->move(p);
}

void MatrixTableWidget::pollCellsData()
{
    // 检测是否存在空值
    for (int r = 0; r < model->rowCount(); ++r) {
        for (int c = 0; c < model->columnCount(); ++c) {
            if (model->item(r, c)->text().isEmpty()) {
                return;
            }
        }
    }

    QTimer::singleShot(0, this, [=]() {
        QStringList nodes;
        QVector<qreal> nxn((int)qPow(model->rowCount(), 2), 0);
        for (int r = 0; r < model->rowCount(); ++r) {
            nodes << model->item(r, 0)->text().trimmed();
            for (int c = 1; c < model->columnCount(); ++c) {
                QStringList content = model->item(r, c)->text().trimmed().split("/");
                if (content.size() == 1) {
                    nxn[r * model->rowCount() + c - 1] = content[0].toDouble();
                } else {
                    nxn[r * model->rowCount() + c - 1] = content[0].toDouble() / content[1].toDouble();
                }
            }
        }

        ConsistencyCheck cc(nodes, nxn);

        if (!cc.consitst()) {
            QMessageBox::warning(this, "一致性校验",
                                 QString("CR:%"
                                         "1\r\n您好,一致性检验未通过!请您检查填写的"
                                         "数据是否有逻辑上的矛盾,例如A比B重"
                                         "要,B比C重要,然后又判断有C比A重要。")
                                         .arg(cc.CR()));
            QStandardItem *item  = model->item(model->rowCount() - 2, model->columnCount() - 1);
            QStandardItem *item1 = model->item(model->columnCount() - 2, model->rowCount() - 1);

            for (int i = 0; i < dataSource.count(); ++i) {
                if (dataSource[i].row == item->row() && dataSource[i].col == item->column()) {
                    dataSource[i].nodeValue = "";
                    item->setText("");
                    dataSource[i].changed = false;
                } else if (dataSource[i].row == item1->row() && dataSource[i].col == item1->column()) {
                    dataSource[i].nodeValue = "";
                    item1->setText("");
                    dataSource[i].changed = false;
                }
            }
        } else {
            // 校验成功持久化数据
            QStringList nodeList   = cc.getNodes();
            QVector<qreal> weights = cc.getWeights();
            qDebug() << weights;
            qDebug() << currentPage;
            QList<DemandWeight *> list;
            if (currentPage == 1) {
                for (int i = 0; i < weights.length(); i++) {
                    DemandWeight *demandWeight = new DemandWeight();
                    demandWeight->nodeName     = nodeList.at(i);
                    demandWeight->nodeWeight   = weights.at(i);
                    demandWeight->engineerId   = m_engineerId;
                    demandWeight->expertId     = m_expertId;
                    demandWeight->isValid      = 0;
                    demandWeight->tableIndex   = m_tableIndex;
                    demandWeight->tableMsg     = m_table_msg;
                    list.append(demandWeight);
                }
            } else {
                // 查询出第一页权重
                QList<DemandWeight *> firstList;
                DemandWeightService().QueryByTableIndexAndTableMsg(&firstList, m_expertId, m_engineerId, 0,
                                                                   m_table_msg);
                qDebug() << "firstList===" << firstList.size();
                double weight = 0;
                if (firstList.size() != 0) {
                    weight = firstList.at(m_tableIndex - 1)->nodeWeight;
                }
                for (int i = 0; i < weights.length(); i++) {
                    DemandWeight *demandWeight = new DemandWeight();
                    demandWeight->nodeName     = nodeList.at(i);
                    demandWeight->nodeWeight   = weights.at(i);
                    demandWeight->engineerId   = m_engineerId;
                    demandWeight->expertId     = m_expertId;
                    demandWeight->isValid      = 0;
                    demandWeight->tableIndex   = m_tableIndex;
                    demandWeight->tableMsg     = m_table_msg;
                    demandWeight->nodeValue    = demandWeight->nodeWeight * weight;
                    list.append(demandWeight);
                }
            }

            if (DemandWeightService().QueryByTableIndexAndTableMsg(m_expertId, m_engineerId, m_tableIndex,
                                                                   m_table_msg)) {
                DemandWeightService().UpdateNodeValueList(list);
            } else {
                DemandWeightService().AddNodeWeightInfoList(list);
            }
            QMessageBox::information(this, "一致性比例合格", QString("CR:%1").arg(cc.CR()));
            // TODO 判断是否是保存后修改后,如保存后修改续自动调用保存
            emit autoSave();
        }
    });
}

void MatrixTableWidget::editItemData(const QModelIndex &index, const QString &val)
{
    model->itemFromIndex(index)->setText(val);
    QString symmetry;
    if (val.startsWith("1/")) {
        symmetry = val.split("/")[1];
    } else {
        if (val == "0" || val == "1") {
            symmetry = val;
        } else {
            symmetry = "1/" + val;
        }
    }
    model->item(index.column() - 1, index.row() + 1)->setText(symmetry);

    QStandardItem *item  = model->itemFromIndex(index);
    QStandardItem *item1 = model->item(index.column() - 1, index.row() + 1);

    for (int i = 0; i < dataSource.count(); ++i) {
        if (dataSource[i].row == item->row() && dataSource[i].col == item->column()) {
            dataSource[i].nodeValue = item->text().trimmed();
            if (!item->text().trimmed().isEmpty()) {
                dataSource[i].changed = true;
            } else {
                dataSource[i].changed = false;
            }
        } else if (dataSource[i].row == item1->row() && dataSource[i].col == item1->column()) {
            dataSource[i].nodeValue = item1->text().trimmed();
            if (!item1->text().trimmed().isEmpty()) {
                dataSource[i].changed = true;
            } else {
                dataSource[i].changed = false;
            }
        }
    }
    pollCellsData();
    emit dataReady(isDataReady());
}

bool MatrixTableWidget::isDataReady() const
{
    if (dataSource.count() == 0) {
        return false;
    }

    for (MatrixDataSource data : dataSource) {
        if (data.changed == false) {
            return false;
        }
    }
    return true;
}