#include "MainWidget.h"
#include <QClipboard>
#include <QSettings>
#include <QFile>
#include <QKeyEvent>
#include "./ui_MainWidget.h"

constexpr std::size_t g_OnePage = 100;

MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget)
{
    ui->setupUi(this);

    setWindowTitle(u8"OneLevelXmlOpr v1.2.6");
    setWindowIcon(QIcon("://resource/xml.ico"));

    setMinimumWidth(900);
    setMinimumHeight(800);

    width_.push_back(280);
    for (int i = 0; i < 30; ++i) {
        width_.push_back(160);
    }

    attri_edit_ = new CAttributeEdit();

    ui->edStatus->setEnabled(false);
    ui->btnSave->setEnabled(false);
    ui->edAllPage->setEnabled(false);
    ui->cbCaseSensitive->setChecked(false);

    connect(ui->btnRead, &QPushButton::clicked, this, [&]() { read(); });
    connect(ui->btnSearch, &QPushButton::clicked, this, [&]() { search(); });
    connect(ui->btnSave, &QPushButton::clicked, this, [&]() { save(); });
    connect(ui->btnExit, &QPushButton::clicked, this, [&]() { QApplication::exit(0); });
    connect(ui->btnReset, &QPushButton::clicked, this, &MainWidget::reset);
    connect(ui->btnPagePre, &QPushButton::clicked, this, [&]() {
        unsigned int cur = ui->edCurPage->text().toUInt();
        push_content(current_, cur - 1);
    });
    connect(ui->btnPageNext, &QPushButton::clicked, this, [&]() {
        unsigned int cur = ui->edCurPage->text().toUInt();
        push_content(current_, cur + 1);
    });
    connect(ui->btnJump, &QPushButton::clicked, this, [&]() {
        unsigned int cur = ui->edCurPage->text().toUInt();
        push_content(current_, cur);
    });

    QSettings settings;
    settings.beginGroup("xmlopr");
    restoreGeometry(settings.value("geometry").toByteArray());
    settings.endGroup();

    QFile qss_file("://qss/flatgray.css");
    if (qss_file.open(QFile::ReadOnly)) {
        qApp->setStyleSheet(qss_file.readAll());
    }

    init_menu();
}

void MainWidget::copy_key()
{
    Element_t* target = get_current_select_key();
    if (target == nullptr) {
        return;
    }
    QClipboard* clip = QApplication::clipboard();
    clip->setText(QString(target->Attribute(keys_[0].c_str())));
    // CUtil::msg(this, u8"已复制");
}

void MainWidget::closeEvent(QCloseEvent* event)
{
    QSettings settings;
    settings.beginGroup("xmlopr");
    settings.setValue("geometry", saveGeometry());
    settings.endGroup();
    QWidget::closeEvent(event);
}

void MainWidget::keyPressEvent(QKeyEvent* event)
{
    switch (event->key()) {
    case Qt::Key_Return:
        search();
        break;
    default:
        break;
    }
    QWidget::keyPressEvent(event);
}

MainWidget::~MainWidget()
{
    delete attri_edit_;
    delete ui;
}

void MainWidget::set_work_exe(char* path)
{
    exe_path_.clear();
    exe_path_.append(path);
}

void MainWidget::generate_table_widget()
{
    tab_widget_ = new QTableWidget();
    tab_widget_->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(tab_widget_, &QTableWidget::itemChanged, this, [&](QTableWidgetItem* item) { item_changed_handle(item); });
    connect(tab_widget_, &QTableWidget::customContextMenuRequested, this, [&]() { context_menu_->exec(QCursor::pos()); });
    auto config = ini_.get_config();
    auto keys = splitString(config.purpose, ",");
    keys_.clear();
    QStringList list;
    for (const auto& item : keys) {
        if (item.empty()) {
            continue;
        }
        keys_.push_back(item);
        list.append(QString::fromStdString(item));
    }

    tab_widget_->setColumnCount(list.size());
    tab_widget_->setHorizontalHeaderLabels(list);
    tab_widget_->setSelectionBehavior(QAbstractItemView::SelectRows);
    tab_widget_->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);

    for (auto i = 0; i < keys.size(); ++i) {
        tab_widget_->setColumnWidth(i, width_[i]);
    }

    QHBoxLayout* lay = new QHBoxLayout();
    lay->addWidget(tab_widget_);
    ui->widget->setLayout(lay);
}

void MainWidget::push_content(const std::vector<tinyxml2::XMLElement*>& eles, std::size_t page)
{
    if (tab_widget_ == nullptr || page == 0) {
        return;
    }

    std::size_t all_size = eles.size();
    std::size_t max_show = g_OnePage * page;
    all_page_ = all_size / 100;

    if (all_size % 100 != 0) {
        ++all_page_;
    }

    if (page < 1 || page > all_page_) {
        if (eles.size() > 0) {
            CUtil::msg(this, u8"页码不在范围内");
            return;
        }
        tab_widget_->clearContents();
        tab_widget_->setRowCount(0);
        cur_page_ = 0;
        ui->edCurPage->setText(QString::number(cur_page_));
        ui->edAllPage->setText(QString::number(all_page_));
        return;
    }

    tab_widget_->clearContents();
    tab_widget_->setRowCount(0);

    for (auto p = (page - 1) * g_OnePage; p < all_size && p < max_show; ++p) {
        int row_cnt = tab_widget_->rowCount();
        tab_widget_->insertRow(row_cnt);
        insert_one_line(eles[p], row_cnt);
    }
    ui->edCurPage->setText(QString::number(page));
    cur_page_ = page;
    ui->edAllPage->setText(QString::number(all_page_));
    judge_btn_page();
}

void MainWidget::judge_btn_page()
{
    int cur = ui->edCurPage->text().trimmed().toUInt();
    if (cur <= 1) {
        ui->btnPagePre->setEnabled(false);
    } else {
        ui->btnPagePre->setEnabled(true);
    }

    if (cur >= all_page_) {
        ui->btnPageNext->setEnabled(false);
    } else {
        ui->btnPageNext->setEnabled(true);
    }
}

void MainWidget::read()
{
    if (!ini_.set_work_exe(exe_path_)) {
        return;
    }
    OprBase base = ini_.get_config();
    if (!xml_.open(base.xml_path)) {
        QString status = u8"Open【" + QString::fromStdString(base.xml_path.c_str()) + u8"】Failed.";
        return;
    }
    xml_.set_baseinfo(base);
    if (!xml_.parse_xml(vec_)) {
        QString status = u8"parse_xml【" + QString::fromStdString(base.xml_path.c_str()) + u8"】Failed.";
        return;
    }

    auto_add_ = true;
    generate_table_widget();
    push_content(vec_);
    current_ = vec_;
    auto_add_ = false;

    QString status = u8"Open And Parse【" + QString::fromLocal8Bit(base.xml_path.c_str()) + u8"】Success.";
    ui->edStatus->setText(status);

    ui->btnRead->setEnabled(false);
    ui->btnSave->setEnabled(true);
}

void MainWidget::search()
{
    QString key = ui->edSearchKey->text().trimmed();
    if (key.isEmpty()) {
        current_ = vec_;
        push_content(current_);
        return;
    }
    if (tab_widget_ == nullptr) {
        return;
    }

    if (!ui->cbCaseSensitive->isChecked()) {
        key = key.toUpper();
    }

    current_.clear();
    for (const auto& item : vec_) {
        for (auto i = 0; i < keys_.size(); ++i) {
            const char* data = item->Attribute(keys_[i].c_str());
            QString     qdata(data);
            if (!ui->cbCaseSensitive->isChecked()) {
                qdata = qdata.toUpper();
            }
            if (!qdata.contains(key)) {
                continue;
            }
            current_.push_back(item);
            break;
        }
    }
    push_content(current_);
}

void MainWidget::item_changed_handle(QTableWidgetItem* item)
{
    if (auto_add_) {
        return;
    }
    if (item == nullptr) {
        return;
    }
    int row = item->row();
    int col = item->column();

    QString    xml_key = tab_widget_->item(row, 0)->text();
    Element_t* result = get_element_bykey(xml_key);
    if (result == nullptr) {
        return;
    }
    result->SetAttribute(keys_[col].c_str(), item->text().toLocal8Bit().constData());
}

void MainWidget::save()
{
    if (xml_.save()) {
        CUtil::msg(this, u8"保存成功");
    } else {
        CUtil::msg(this, u8"保存失败");
    }
}

void MainWidget::copy_select_line()
{
    // if (!CUtil::affirm(this, u8"确认", u8"确认复制吗?")) {
    //     return;
    // }

    QTableWidgetItem* cur_item = get_current_select_item();
    if (cur_item == nullptr) {
        return;
    }

    Element_t* target = get_element_bykey(cur_item->text());
    if (target == nullptr) {
        return;
    }
    Element_t* newer = xml_.copy_element(target);

    if (!edit_property(newer, cur_item->row())) {
        return;
    }

    xml_.insert_brother_node(target, newer);

    tab_widget_->insertRow(cur_item->row() + 1);
    insert_one_line(newer, cur_item->row() + 1);

    std::vector<Element_t*>::iterator it;
    for (it = vec_.begin(); it != vec_.end(); ++it) {
        if (*it == target) {
            break;
        }
    }
    int df = it - vec_.begin() + 1;
    vec_.insert(vec_.begin() + df, newer);
    search();
}

// 返回 true 表示确认编辑了, false 表示取消编辑了。
bool MainWidget::edit_property(Element_t* target, int row)
{
    if (target == nullptr) {
        return false;
    }

    Property_t property;
    xml_.get_key_value(target, property);

    // 检测key值是否变化
    std::string value_pre = property[0].value;
    attri_edit_->set_attribute(property);
    attri_edit_->exec();

    if (!attri_edit_->is_ok_) {
        return false;
    }

    attri_edit_->get_attribute(property);
    if (property[0].value != value_pre) {
        while (xml_.check_key_exists(property)) {
            CUtil::msg(attri_edit_, u8"不能有相同的key,请检查。");
            attri_edit_->exec();
            attri_edit_->get_attribute(property);
            if (!attri_edit_->is_ok_) {
                return false;
            }
        }
    }
    xml_.key_value_to_element(target, property);

    // 这里要同步到界面
    ele_update_gui(target, row);
    return true;
}

void MainWidget::ele_update_gui(Element_t* target, int row)
{
    if (tab_widget_ == nullptr) {
        return;
    }
    for (auto i = 0; i < keys_.size(); ++i) {
        const char* v = target->Attribute(keys_[i].c_str());
        auto*       qitem = tab_widget_->item(row, i);
        qitem->setText(QString(v));
    }
}

void MainWidget::init_menu()
{
    context_menu_ = new QMenu();
    ac_edit_property_ = new QAction(u8"编辑");
    ac_copy_curline_ = new QAction(u8"复制此项");
    ac_del_curline_ = new QAction(u8"删除此项");
    ac_copy_key_ = new QAction(u8"复制key");

    context_menu_->addAction(ac_edit_property_);
    context_menu_->addAction(ac_copy_curline_);
    context_menu_->addAction(ac_del_curline_);
    context_menu_->addAction(ac_copy_key_);

    connect(ac_edit_property_, &QAction::triggered, this, [&]() {
        QTableWidgetItem* cur_item = get_current_select_item();
        if (cur_item == nullptr) {
            return;
        }

        Element_t* target = get_element_bykey(cur_item->text());
        if (target == nullptr) {
            return;
        }
        edit_property(target, cur_item->row());
    });
    connect(ac_copy_curline_, &QAction::triggered, this, [&]() { copy_select_line(); });
    connect(ac_del_curline_, &QAction::triggered, this, [&]() { del_select_line(); });
    connect(ac_copy_key_, &QAction::triggered, this, [&]() { copy_key(); });
}

void MainWidget::insert_one_line(Element_t* ele, int row)
{
    if (ele == nullptr) {
        return;
    }
    for (auto i = 0; i < keys_.size(); ++i) {
        const char*       data = ele->Attribute(keys_[i].c_str());
        QTableWidgetItem* wgItem = new QTableWidgetItem();

        if (i == 0) {
            wgItem->setFlags(wgItem->flags() & ~Qt::ItemIsEditable);
        }

        wgItem->setText(QString(data));
        tab_widget_->setItem(row, i, wgItem);
    }
}

void MainWidget::del_select_line()
{
    if (!CUtil::affirm(this, u8"确认", u8"确认删除吗?")) {
        return;
    }
    QTableWidgetItem* item = get_current_select_item();
    if (item == nullptr) {
        return;
    }
    Element_t* target = get_element_bykey(item->text());
    if (target == nullptr) {
        return;
    }
    xml_.del_element(target);

    // TODO: 添加到界面
    tab_widget_->removeRow(item->row());

    std::vector<Element_t*>::iterator it;
    for (it = vec_.begin(); it != vec_.end(); ++it) {
        if (*it == target) {
            break;
        }
    }
    vec_.erase(it);
    search();
}

Element_t* MainWidget::get_current_select_key()
{
    Element_t*        ret = nullptr;
    QTableWidgetItem* item = get_current_select_item();
    if (item == nullptr) {
        return ret;
    }
    ret = get_element_bykey(item->text());
    return ret;
}

QTableWidgetItem* MainWidget::get_current_select_item()
{
    QTableWidgetItem* ret = nullptr;
    if (tab_widget_ == nullptr) {
        return ret;
    }
    QList<QTableWidgetItem*> selectedItems = tab_widget_->selectedItems();
    if (selectedItems.size() < 1) {
        CUtil::msg(this, u8"没有选中数据");
        return ret;
    }
    ret = selectedItems[0];
    return ret;
}

void MainWidget::reset()
{
    current_.clear();
    current_ = vec_;
    push_content(current_);
}

tinyxml2::XMLElement* MainWidget::get_element_bykey(const QString& key)
{
    Element_t* ret = nullptr;
    for (const auto& ele : current_) {
        const char* data = ele->Attribute(keys_[0].c_str());
        QString     qdata(data);
        if (qdata != key) {
            continue;
        }
        ret = ele;
        break;
    }
    return ret;
}