#include "storychainspresent.h"
#include "DocsManager.h"
#include "command_list.h"
#include "manager_docs.h"

#include <QSplitter>
#include <QVBoxLayout>

using namespace Components;
using namespace Parse;
using namespace Parse::Result;
using namespace Tools;
using namespace CommandList;
using namespace DataModel;

StorychainsPresentModel::StorychainsPresentModel(Core::AppCore *core)
    : core_ins(core), model_base(new QStandardItemModel),
      details_base(new QTextDocument) {
    sync_tools = new TreeSyncs<DesNode *>(
        model_base,
        [](DesNode *const &d, QStandardItem *it) -> bool {
            return static_cast<NamedNode *>(d)->name().first() == it->text();
        },
        [](DesNode *const &d, QStandardItem *it) {
            it->setText(static_cast<NamedNode *>(d)->name().first());
        });
}

StorychainsPresentModel::~StorychainsPresentModel() {
    delete model_base;
    delete details_base;
    delete sync_tools;
}

QStandardItemModel *StorychainsPresentModel::treeModel() const {
    return model_base;
}

QTextDocument *const StorychainsPresentModel::detailsBackend() const {
    return details_base;
}

void StorychainsPresentModel::refreshTree() {
    sync_tools->presentSync([this](DesNode *p) -> QList<DesNode *> {
        if (p) {
            QList<DesNode *> retv;
            for (auto &point : p->children()) {
                if (point->typeValue() == NODE_STORYPOINT) {
                    retv << point;
                }
            }
            return retv;
        } else
            return this->core_ins->parseCore()->allStoryChains();
    });
}

using namespace Operate;
void StorychainsPresentModel::showDetails(const QList<QString> &chain_path) {
    QStandardItem *item = nullptr;
    // 迭代路径获取故事链节点
    for (auto &it : chain_path) {
        auto result = OpStream<QStandardItem *>([this, &item](int &cnt, int idx) -> QStandardItem * {
                          if (!item) {
                              cnt = model_base->rowCount();
                              if (cnt <= 0)
                                  return nullptr;
                              return model_base->item(idx);
                          } else {
                              cnt = item->rowCount();
                              if (cnt <= 0)
                                  return nullptr;
                              return item->child(idx);
                          }
                      }).filter([it](QStandardItem *const &xit) {
                            return it == xit->text();
                        }).toList();

        if (!result.size()) {
            throw new SimpleException("指定的Storychain路径无效：" +
                                      chain_path.join("/"));
        } else {
            item = result.at(0);
        }
    }

    // 填充详细内容
    QString text_lines;
    if (item->parent() == nullptr) {
        auto node = core_ins->parseCore()->queryStoryChain(item->text());

        auto children = node.first()->children();
        for (auto &it : children) {
            if (it->typeValue() != NODE_STORYPOINT) {
                text_lines += it->toString() + "\n";
            }
        }
    } else {
        auto node =
            core_ins->parseCore()->queryStoryChain(item->parent()->text());
        auto point =
            core_ins->parseCore()->queryStoryPoint(node.first(), item->text());

        auto children = point.first()->children();
        for (auto &it : children) {
            text_lines += it->toString() + "\n";
        }
    }

    details_base->setPlainText(text_lines);
}

QString StorychainsPresentModel::name() const {
    return NAME(StorychainsPresentModel);
}

StorychainsPresent::StorychainsPresent(Schedule::CommandsDispatcher *disp, StorychainsPresentModel *backend, QWidget *parent)
    : QWidget(parent), disp_core(disp), tree_view(new QTreeView(this)), details_show(new QTextEdit) {

    tree_view->setModel(backend->treeModel());
    tree_view->setHeaderHidden(true);
    details_show->setDocument(backend->detailsBackend());
    details_show->setReadOnly(true);

    auto layoutx = new QVBoxLayout(this);
    auto split = new QSplitter(Qt::Vertical, this);
    layoutx->addWidget(split);
    split->addWidget(tree_view);
    split->addWidget(details_show);
    layoutx->setMargin(0);

    connect(tree_view, &QTreeView::clicked, this,
            &StorychainsPresent::detail_show);
    connect(tree_view, &QTreeView::doubleClicked, this,
            &StorychainsPresent::jump_to);
}

QString StorychainsPresent::name() const { return NAME(StorychainsPresent); }

QWidget *StorychainsPresent::widget() const { return (QWidget *)this; }

void StorychainsPresent::jump_to(const QModelIndex &curr) {
    if (!curr.isValid())
        return;

    QList<QString> path;
    auto node = curr;
    while (true) {
        auto node_name = node.data().toString();

        if (node_name.isEmpty())
            break;
        path.insert(0, node_name);
        node = node.parent();
    }

    disp_core->postCommand(StorychainJumpTo(path));
}

void StorychainsPresent::detail_show(const QModelIndex &curr) {
    if (!curr.isValid())
        return;

    QList<QString> path;
    auto node = curr;
    while (true) {
        auto node_name = node.data().toString();

        if (node_name.isEmpty())
            break;
        path.insert(0, node_name);
        node = node.parent();
    }

    disp_core->postCommand(StorychainDetailShow(path));
}
