#include "MainWidget.h"
#include <QClipboard>
#include <QSettings>
#include <QFile>
#include <QKeyEvent>
#include <QDateTime>
#include <QScreen>
#include <QRegularExpression>
#include <filesystem>
#include "src/data_edit.h"
#include "./ui_MainWidget.h"

constexpr std::size_t g_OnePage = 100;
namespace fs = std::filesystem;
MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget)
{
    ui->setupUi(this);

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

    QScreen* primaryScreen = QGuiApplication::primaryScreen();
    QRect    screenGeometry = primaryScreen->geometry();
    setMinimumWidth(screenGeometry.width() * 0.5);
    setMinimumHeight(screenGeometry.height() * 0.9);
    // 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->setReadOnly(true);
    ui->btnSave->setEnabled(false);
    ui->edAllPage->setEnabled(false);
    ui->cbCaseSensitive->setChecked(false);
    ui->btnImport->setEnabled(false);
    ui->btnExport->setEnabled(false);
    ui->btnBackup->setEnabled(false);
    ui->rbReplaceSelect->setChecked(true);
    ui->btnRead->setFixedWidth(100);
    ui->btnSave->setFixedWidth(100);
    ui->btnExit->setFixedWidth(100);

    connect(ui->btnSelectFile, &QPushButton::clicked, this, [&]() {
        QString file = CUtil::select_file(this, u8"请选择xml文件", u8"XML(*.xml);;所有文件 (*)");
        if (file.isEmpty()) {
            return;
        }
        read(file);
    });
    connect(ui->btnSearch, &QPushButton::clicked, this, [&]() { search(ui->edSearchKey->text()); });
    connect(ui->btnBackup, &QPushButton::clicked, this, [&]() { backup_file(); });
    connect(ui->btnRead, &QPushButton::clicked, this, [&]() { read(ui->edStatus->text().trimmed()); });
    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->btnReplace, &QPushButton::clicked, this, [&]() { replace_content(true); });
    connect(ui->btnRxReplace, &QPushButton::clicked, this, [&]() { replace_content(false); });
    connect(ui->btnExport, &QPushButton::clicked, this, &MainWidget::copy_multi_data);
    connect(ui->btnPagePre, &QPushButton::clicked, this, [&]() {
        unsigned int cur = ui->edCurPage->text().toUInt();
        push_content(current_, cur - 1);
    });
    connect(ui->btnImport, &QPushButton::clicked, this, [&]() {
        CDataEdit edit;
        edit.is_import_ = true;
        edit.set_xml_opr(&xml_);
        edit.exec();

        if (!edit.is_import_sucess_) {
            return;
        }
        xml_.get_all_elements(vec_);
        current_.clear();
        current_ = vec_;
        push_content(current_);
    });
    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);
    });
    connect(ui->btnResort, &QPushButton::clicked, this, [&]() {
        if (tab_widget_ == nullptr) {
            return;
        }
        sort_by_repeat(vec_);
        std::vector<Element_t*> nvec{};
        xml_.copy_and_del(vec_, nvec);
        vec_.clear();
        std::swap(vec_, nvec);
        current_ = vec_;
        push_content(current_);
    });

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

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

    init_menu();

    ini_.set_work_exe(exe_path_);
    base_ = ini_.get_config();
    ui->edStatus->setText(QString::fromStdString(base_.xml_path));
}

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(ui->edSearchKey->text());
        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::show_custom_menu()
{
    if (tab_widget_ == nullptr) {
        return;
    }
    QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows();

    if (indexList.size() == 1) {
        menu_simple_->exec(QCursor::pos());
    }
    else {
        menu_multi_->exec(QCursor::pos());
    }
}

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, &MainWidget::show_custom_menu);
    auto config = ini_.get_config();
    auto keys = CUtil::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);

    auto_add_ = true;
    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();
    auto_add_ = false;
}

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(const QString& file_path)
{
    if (!ini_.set_xml_path(file_path.toStdString())) {
        CUtil::msg(this, u8"没有ini配置文件或者保存ini失败。");
        return;
    }
    ui->edStatus->setText(file_path);

    if (!xml_.open(base_.xml_path)) {
        CUtil::msg(this, u8"打开xml失败。");
        return;
    }
    xml_.set_baseinfo(base_);
    if (!xml_.parse_xml(vec_)) {
        CUtil::msg(this, u8"解析xml失败。");
        return;
    }

    generate_table_widget();
    push_content(vec_);
    current_ = vec_;

    ui->edStatus->setText(file_path);
    ui->btnRead->setEnabled(false);
    ui->btnSave->setEnabled(true);
    ui->btnSelectFile->setEnabled(false);
    ui->btnImport->setEnabled(true);
    ui->btnExport->setEnabled(true);
    ui->btnBackup->setEnabled(true);
}

void MainWidget::search(const QString& key)
{
    QString bkey = key;
    if (bkey.isEmpty()) {
        current_ = vec_;
        push_content(current_);
        return;
    }
    if (tab_widget_ == nullptr) {
        return;
    }

    if (!ui->cbCaseSensitive->isChecked()) {
        bkey = bkey.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(bkey)) {
                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_by_key(xml_key);
    if (result == nullptr) {
        return;
    }
    result->SetAttribute(keys_[col].c_str(), item->text().toStdString().c_str());
}

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_by_key(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(ui->edSearchKey->text());
}

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

    Property_t property;
    xml_.get_attributes(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_.attributes_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()
{
    menu_simple_ = new QMenu();
    menu_multi_ = 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");

    menu_simple_->addAction(ac_edit_property_);
    menu_simple_->addAction(ac_copy_curline_);
    menu_simple_->addAction(ac_del_curline_);
    menu_simple_->addAction(ac_copy_key_);
    menu_multi_->addAction(ac_del_curline_);

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

        Element_t* target = get_element_by_key(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->setFlags(wgItem->flags() | Qt::ItemIsUserCheckable);
            // wgItem->setCheckState(Qt::Checked);
        }
        QString sda(data);
        wgItem->setText(sda);
        tab_widget_->setItem(row, i, wgItem);
    }
}

void MainWidget::del_select_line()
{
    if (!CUtil::affirm(this, u8"确认", u8"确认删除吗?")) {
        return;
    }

    QModelIndexList  indexList = tab_widget_->selectionModel()->selectedRows();
    int              size = indexList.size();
    std::vector<int> erase_row;
    for (auto i = size - 1; i > -1; --i) {
        Element_t* target = get_element_by_row(indexList[i].row());
        if (target == nullptr) {
            continue;
        }
        xml_.del_element(target);
        tab_widget_->removeRow(indexList[i].row());
        erase_row.push_back(indexList[i].row());
        std::vector<Element_t*>::iterator it;
        for (it = vec_.begin(); it != vec_.end(); ++it) {
            if (*it == target) {
                break;
            }
        }
        vec_.erase(it);
    }
    // std::sort(erase_row.begin(), erase_row.end(), std::greater<int>());
    // for (const auto& item : erase_row) {
    //     tab_widget_->removeRow(item);
    // }
    search(ui->edSearchKey->text());
}

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_by_key(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_by_key(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;
}

Element_t* MainWidget::get_element_by_row(int row)
{
    Element_t* ret = nullptr;
    if (row < 0 || !tab_widget_ || row >= tab_widget_->rowCount()) {
        return ret;
    }
    QTableWidgetItem* item = tab_widget_->item(row, 0);
    ret = get_element_by_key(item->text());
    return ret;
}

void MainWidget::sort_by_repeat(std::vector<Element_t*>& vec)
{

    std::vector<SElement_t> turn_vec{};
    for (const auto& item : vec) {
        const char* str = item->Attribute(keys_[0].c_str());
        turn_vec.emplace_back(item, std::string(str));
    }

    auto compare = [&](const SElement_t& se1, const SElement_t& se2) {
        std::size_t i = 0;
        // 逐个字符比较,直到找到不同的字符或者某个字符串到达结尾
        while (i < se1.str.length() && i < se2.str.length()) {
            if (se1.str[i] != se2.str[i]) {
                return se1.str[i] < se2.str[i];
            }
            ++i;
        }
        // 如果有一个字符串到达结尾,而另一个还没有,则较短的字符串排在前面
        return se1.str.length() < se2.str.length();
    };
    std::sort(turn_vec.begin(), turn_vec.end(), compare);
    vec.clear();
    for (const auto& item : turn_vec) {
        vec.push_back(item.ele);
    }
}

void MainWidget::copy_multi_data()
{
    if (tab_widget_ == nullptr) {
        return;
    }
    std::vector<OperElement*> vec;
    
    if (ui->rbAllPage->isChecked()) {
        get_related_elements(vec, AREA_ALL_PAGE);
    }
    else if (ui->rbReplaceSelect->isChecked()) {
        get_related_elements(vec, AREA_SELECT);
    }
    else if (ui->rbRepCurPage->isChecked()) {
        get_related_elements(vec, AREA_CUR_PAGE);
    }
    else {
        get_related_elements(vec, AREA_ALL);
    }

    if (vec.size() < 1) {
        CUtil::msg(this, u8"无选择数据");
        return;
    }
    QString ret;
    for (auto& item : vec) {
        if (item == nullptr) {
            continue;
        }
        tinyxml2::XMLPrinter printer;
        item->element_->Accept(&printer);
        ret.append(printer.CStr());
        delete item;
    }

    CDataEdit edit;
    edit.set_data(ret);
    edit.exec();
}

void MainWidget::replace_content(bool is_common)
{
    if (tab_widget_ == nullptr) {
        return;
    }
    QString key = ui->edRepPre->text();
    QString after = ui->edRepAfter->text();
    if (key.isEmpty()) {
        CUtil::msg(this, u8"替换前数据为空。");
        return;
    }
    auto handle = [&](const std::vector<OperElement*>& vec, bool is_search) {
        for (auto& item : vec) {
            if (is_common) {
                replace_str(key, after, item->element_);
            } else {
                replace_str(item->element_, key, after);
            }
            if (!is_search) {
                ele_update_gui(item->element_, item->row_);
            }
            delete item;
        }
    };

    std::vector<OperElement*> vec;
    if (ui->rbReplaceSelect->isChecked()) {
        QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows();
        if (indexList.size() < 1) {
            CUtil::msg(this, u8"无选择数据");
            return;
        }
        get_related_elements(vec, AREA_SELECT);
        handle(vec, false);
    } else if (ui->rbAllPage->isChecked()) {
        get_related_elements(vec, AREA_ALL_PAGE);
        handle(vec, false);
        xml_.get_all_elements(vec_);
        current_.clear();
        current_ = vec_;
        search(ui->edRepAfter->text());
    } else if (ui->rbRepCurPage->isChecked()) {
        get_related_elements(vec, AREA_CUR_PAGE);
        handle(vec, false);
    } else {
        if (!CUtil::affirm(this, u8"确认", u8"确认进行全局替换吗?")) {
            return;
        }
        get_related_elements(vec, AREA_ALL);
        handle(vec, true);
        xml_.get_all_elements(vec_);
        current_.clear();
        current_ = vec_;
        search(ui->edSearchKey->text());
    }
}

void MainWidget::replace_str(const QString& pre, const QString& after, Element_t* ele)
{
    if (ele == nullptr) {
        return;
    }
    for (auto i = 0; i < keys_.size(); ++i) {
        auto*   value = ele->Attribute(keys_[i].c_str());
        QString content(value);
        if (content.contains(pre)) {
            content.replace(pre, after);
            ele->SetAttribute(keys_[i].c_str(), content.toStdString().c_str());
        }
    }
}

void MainWidget::replace_str(Element_t* ele, const QString& rg, const QString& after)
{
    QRegularExpression rx(rg);
    if (ele == nullptr) {
        return;
    }
    for (auto i = 0; i < keys_.size(); ++i) {
        auto*   value = ele->Attribute(keys_[i].c_str());
        QString content(value);
        content.replace(rx, after);
        ele->SetAttribute(keys_[i].c_str(), content.toStdString().c_str());
    }
}

void MainWidget::get_related_elements(std::vector<OperElement*>& out, ReplaceArea area)
{
    assert(tab_widget_);
    out.clear();
    switch (area) {
    case AREA_ALL_PAGE: {
        out.resize(current_.size());
        std::transform(current_.begin(), current_.end(), out.begin(),
                       [](Element_t* ele) { return new OperElement(ele, 0); });
        break;
    }
    case AREA_CUR_PAGE: {
        int rows = tab_widget_->rowCount();
        for (int i = 0; i < rows; ++i) {
            out.emplace_back(new OperElement(get_element_by_row(i), i));
        }
        break;
    }
    case AREA_ALL: {
        out.resize(vec_.size());
        std::transform(vec_.begin(), vec_.end(), out.begin(),
                       [](Element_t* ele) { return new OperElement(ele, 0); });
        break;
    }
    default: {
        QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows();
        for (int i = 0; i < indexList.size(); ++i) {
            out.emplace_back(new OperElement(get_element_by_row(indexList[i].row()), indexList[i].row()));
        }
        break;
    }
    }
}

void MainWidget::backup_file()
{
    if (tab_widget_ == nullptr) {
        return;
    }

    QString time = QDateTime::currentDateTime().toString("yyyy-MMdd-hhmmss");
    if (!xml_.backup_file(fs::path(exe_path_).parent_path().append("backup").string(), time.toStdString())) {
        CUtil::msg(this, u8"备份失败。");
    } else {
        CUtil::msg(this, u8"备份完成。");
    }
}

OperElement::OperElement(Element_t* ele, int row)
{
    element_ = ele;
    row_ = row;
}

SElement_t::SElement_t(Element_t* e, std::string& s)
{
    ele = e;
    str = std::move(s);
}