#include "storyunitspresent.h"
#include "DocsManager.h"
#include "command_list.h"
#include "opstream.h"

#include <QSplitter>
#include <QVBoxLayout>

using namespace Components;
using namespace Parse::Result;
using namespace Operate;
using namespace DataModel;

StoryunitsPresentModel::StoryunitsPresentModel(Core::AppCore *core)
    : core_ins(core), model_ins(new QStandardItemModel),
      details_backend(new QTextDocument) {}

StoryunitsPresentModel::~StoryunitsPresentModel() {
    delete model_ins;
    delete details_backend;
}

QStandardItemModel *StoryunitsPresentModel::treeModel() const {
    return model_ins;
}

QTextDocument *StoryunitsPresentModel::detailsBackend() const {
    return details_backend;
}

void StoryunitsPresentModel::refreshTree() {
    model_ins->clear();
    auto units = core_ins->parseCore()->allStoryUnits();
    for (auto &unit : units) {
        auto unit_node =
            new QStandardItem(static_cast<NamedNode *>(unit)->name()[0]);
        unit_node->setEditable(false);
        model_ins->appendRow(unit_node);

        auto children = unit->children();
        for (auto &frag : children) {
            if (frag->typeValue() == NODE_STORYFRAGMENT) {
                auto frag_node = new QStandardItem(
                    static_cast<NamedNode *>(frag)->name()[0]);
                frag_node->setEditable(false);
                unit_node->appendRow(frag_node);
            }
        }
    }
}

void StoryunitsPresentModel::details_show(const QList<QString> &path) {
    QStandardItem *item = nullptr;
    // 迭代路径获取故事链节点
    for (auto &it : path) {
        auto result = OpStream<QStandardItem *>([this, &item](int &cnt, int idx) -> QStandardItem * {
                          if (!item) {
                              cnt = model_ins->rowCount();
                              if (cnt <= 0)
                                  return nullptr;
                              return model_ins->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路径无效：" + path.join("/"));
        } else {
            item = result.at(0);
        }
    }

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

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

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

    details_backend->setPlainText(contents);
}

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

StoryunitsPresent::StoryunitsPresent(Schedule::CommandsDispatcher *core, StoryunitsPresentModel *backend, QWidget *parent)
    : QWidget(parent), disp_core(core), units_view(new QTreeView(this)), details_show(new QTextEdit(this)) {
    units_view->setHeaderHidden(true);
    units_view->setModel(backend->treeModel());
    details_show->setReadOnly(true);
    details_show->setDocument(backend->detailsBackend());

    auto layout = new QVBoxLayout(this);
    auto splitter = new QSplitter(Qt::Vertical, this);
    layout->addWidget(splitter);
    splitter->addWidget(units_view);
    splitter->addWidget(details_show);
    layout->setMargin(0);

    connect(units_view, &QTreeView::clicked, this,
            &StoryunitsPresent::show_details);
    connect(units_view, &QTreeView::doubleClicked, this,
            &StoryunitsPresent::jump_to);
}

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

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

using namespace CommandList;
void StoryunitsPresent::jump_to(const QModelIndex &curr) {
    QList<QString> path;
    QModelIndex 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(StoryunitJumpTo(path));
}

void StoryunitsPresent::show_details(const QModelIndex &curr) {
    QList<QString> path;
    QModelIndex 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(StoryunitDetailShow(path));
}
