#include "CompareControl.h"

#include <QDesktopServices>
#include <QDialogButtonBox>
#include <QDir>
#include <QFile>
#include <QListWidget>
#include <QMessageBox>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>

#include "Form/Loading.h"
#include "GuiUtil/Public.h"
#include "ui_CompareControl.h"

Compare::Compare(QWidget* parent) : QWidget(parent), ui(new Ui::Compare)
{
    ui->setupUi(this);
    InitControl();
    InitMenu();
}

Compare::~Compare()
{
    delete ui;
}

void Compare::InitMenu()
{
    menu_ = new QMenu(ui->tableWidget);
    menu_->addAction(tr("尝试访问本地路径"), this, [this]() {
        auto selected = ui->tableWidget->selectedItems();
        if (selected.size() != 3) {
            return;
        }
        auto item = selected[1];
        auto path = item->text();
        emit sigTryVisit(true, path);
    });
    menu_->addAction(tr("尝试访问远程路径"), this, [this]() {
        auto selected = ui->tableWidget->selectedItems();
        if (selected.size() != 3) {
            return;
        }
        auto item = selected[2];
        auto path = item->text();
        emit sigTryVisit(false, path);
    });
    menu_->addAction(tr("尝试打开本地路径"), this, [this]() {
        auto selected = ui->tableWidget->selectedItems();
        if (selected.size() != 3) {
            return;
        }
        auto item = selected[1];
        auto path = item->text();
        QDir dir(path);
        if (!dir.exists()) {
            FTCommon::msg(this, tr("本地路径不存在。"));
            return;
        }
        QDesktopServices::openUrl(QUrl::fromLocalFile(path));
    });
    menu_->addAction(tr("添加新行"), this, [this]() {
        int cnt = ui->tableWidget->rowCount();
        ui->tableWidget->insertRow(cnt);
        auto item1 = new QTableWidgetItem("");
        auto item2 = new QTableWidgetItem("");
        auto item3 = new QTableWidgetItem("");
        ui->tableWidget->setItem(cnt, 0, item1);
        ui->tableWidget->setItem(cnt, 1, item2);
        ui->tableWidget->setItem(cnt, 2, item3);
    });
    menu_->addAction(tr("删除"), this, [this]() { deleteSelectedRows(); });
    menu_->addAction(tr("上传"), this, [this]() { TransToRight(false); });
    menu_->addAction(tr("下载"), this, [this]() { TransToLeft(false); });
    menu_->addSeparator();
    connect(ui->tableWidget, &QTableWidget::customContextMenuRequested, this,
            [this](const QPoint& pos) { menu_->exec(QCursor::pos()); });
}

void Compare::InitControl()
{
    InitTabWidget();

    connect(ui->btnSave, &QPushButton::clicked, this, &Compare::Save);
    connect(ui->btnLoad, &QPushButton::clicked, this, &Compare::Load);
    // connect(ui->btnLeft, &QPushButton::clicked, this, &Compare::TransToLeft);
    // connect(ui->btnRight, &QPushButton::clicked, this, &Compare::TransToRight);
    connect(ui->btnTypeDown, &QPushButton::clicked, this, [this]() { FilterFiles(false); });
    connect(ui->btnTypeUpload, &QPushButton::clicked, this, [this]() { FilterFiles(true); });
    connect(ui->btnSearch, &QPushButton::clicked, this, &Compare::Search);
    connect(ui->btnReset, &QPushButton::clicked, this, &Compare::Reset);

    // 测试代码
    connect(ui->btnReplace, &QPushButton::clicked, this, [this]() {
        // auto* loading = new LoadingDialog(this);
        // loading->exec();
    });

    LoadTitles();

    isResource_ = true;
    ui->tableWidget->setIsResource(isResource_);
}

void Compare::InitTabWidget()
{
    QStringList headers;
    headers << tr("文件") << tr("本地目录") << tr("远端目录");
    ui->tableWidget->setColumnCount(headers.size());
    ui->tableWidget->setHorizontalHeaderLabels(headers);
    ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);

    ui->comboBox->setEditable(true);
    // ui->tableWidget->setColumnWidth(0, 50);
    ui->tableWidget->setColumnWidth(0, 400);
    /// ui->tableWidget->setColumnWidth(1, 300);
    ui->tableWidget->setColumnWidth(2, 300);

    ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    // ui->tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    // ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
    ui->tableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
    ui->tableWidget->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
    ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);

    ui->tableWidget->setDragEnabled(false);
    ui->tableWidget->viewport()->setAcceptDrops(true);
    ui->tableWidget->setDropIndicatorShown(true);
    ui->tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
    ui->tableWidget->setDragDropMode(QAbstractItemView::DropOnly);

    ui->comboBox->setFixedWidth(100);
}

void Compare::Save()
{
    auto titleKey = ui->comboBox->currentText().trimmed();
    if (titleKey.isEmpty()) {
        FTCommon::msg(this, tr("请输入标题"));
        return;
    }

    if (!isResource_) {
        QMessageBox::information(this, tr("提示"), tr("请先重置搜索结果后操作。"));
        return;
    }

    QFile file("CompareData.xml");
    if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
        FTCommon::msg(this, tr("打开数据文件失败。"));
        return;
    }

    QString existingContent;
    QMap<QString, QStringList> dataMap;
    if (file.size() > 0) {
        existingContent = file.readAll();
        file.seek(0);
        QXmlStreamReader reader(existingContent);
        while (!reader.atEnd()) {
            if (reader.isStartElement() && reader.name() == "Entry") {
                QString key = reader.attributes().value("title").toString();
                QStringList paths;
                while (!(reader.isEndElement() && reader.name() == "Entry")) {
                    reader.readNext();
                    if (reader.isStartElement() && reader.name() == "FileName") {
                        paths << reader.readElementText();
                    }
                    if (reader.isStartElement() && reader.name() == "LocalDir") {
                        paths << reader.readElementText();
                    }
                    if (reader.isStartElement() && reader.name() == "RemoteDir") {
                        paths << reader.readElementText();
                    }
                }
                dataMap.insert(key, paths);
            }
            reader.readNext();
        }
    }

    QStringList paths;
    items_.clear();

    for (int row = 0; row < ui->tableWidget->rowCount(); ++row) {
        QTableWidgetItem* fileName = ui->tableWidget->item(row, 0);
        QTableWidgetItem* localItem = ui->tableWidget->item(row, 1);
        QTableWidgetItem* remoteItem = ui->tableWidget->item(row, 2);

        auto baseName = (fileName ? fileName->text() : "");
        auto localDir = (localItem ? localItem->text() : "");
        auto remoteDir = (remoteItem ? remoteItem->text() : "");

        CompareItem item;
        item.baseName = baseName;
        item.localDir = localDir;
        item.remoteDir = remoteDir;
        items_.push_back(item);

        paths << baseName;
        paths << localDir;
        paths << remoteDir;
    }

    dataMap[titleKey] = paths;

    file.resize(0);
    QXmlStreamWriter writer(&file);
    writer.setAutoFormatting(true);
    writer.writeStartDocument();
    writer.writeStartElement("CompareData");

    for (auto it = dataMap.begin(); it != dataMap.end(); ++it) {
        writer.writeStartElement("Entry");
        writer.writeAttribute("title", it.key());

        const QStringList& pathList = it.value();
        for (int i = 0; i < pathList.size(); i += 3) {
            writer.writeTextElement("FileName", pathList[i]);
            writer.writeTextElement("LocalDir", pathList[i + 1]);
            writer.writeTextElement("RemoteDir", pathList[i + 2]);
        }

        writer.writeEndElement();
    }

    writer.writeEndElement();
    writer.writeEndDocument();
    file.close();

    if (ui->comboBox->findText(titleKey) == -1) {
        ui->comboBox->addItem(titleKey);
    }

    FTCommon::msg(this, tr("数据保存成功。"));
}

void Compare::Load()
{
    auto titleKey = ui->comboBox->currentText().trimmed();
    if (titleKey.isEmpty()) {
        FTCommon::msg(this, tr("请选择或输入标题。"));
        return;
    }

    QFile file("CompareData.xml");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        FTCommon::msg(this, tr("打开数据文件失败。"));
        return;
    }

    items_.clear();
    isResource_ = true;
    ui->tableWidget->setIsResource(isResource_);
    QXmlStreamReader reader(&file);
    bool found = false;

    ui->tableWidget->setRowCount(0);
    while (!reader.atEnd() && !found) {
        if (reader.isStartElement() && reader.name() == "Entry") {
            if (reader.attributes().value("title").toString() == titleKey) {
                found = true;
                QStringList paths;

                while (!(reader.isEndElement() && reader.name() == "Entry")) {
                    reader.readNext();
                    if (reader.isStartElement() && reader.name() == "FileName") {
                        paths << reader.readElementText();
                    }
                    if (reader.isStartElement() && reader.name() == "LocalDir") {
                        paths << reader.readElementText();
                    }
                    if (reader.isStartElement() && reader.name() == "RemoteDir") {
                        paths << reader.readElementText();
                    }
                }
                for (int i = 0; i < paths.size(); i += 3) {
                    int row = ui->tableWidget->rowCount();
                    ui->tableWidget->insertRow(row);

                    CompareItem item;
                    item.baseName = paths[i];
                    item.localDir = paths[i + 1];
                    item.remoteDir = paths[i + 2];
                    items_.push_back(item);

                    QTableWidgetItem* fileName = new QTableWidgetItem(paths[i]);
                    QTableWidgetItem* localItem = new QTableWidgetItem(paths[i + 1]);
                    QTableWidgetItem* remoteItem = new QTableWidgetItem(paths[i + 2]);

                    ui->tableWidget->setItem(row, 0, fileName);
                    ui->tableWidget->setItem(row, 1, localItem);
                    ui->tableWidget->setItem(row, 2, remoteItem);
                }
            }
        }
        reader.readNext();
    }

    file.close();
    if (!found) {
        FTCommon::msg(this, tr("没有找到标题对应的数据。"));
    } else {
        // FTCommon::msg(this, tr("Data loaded successfully."));
    }
}

void Compare::LoadTitles()
{
    QFile file("CompareData.xml");
    if (!file.exists()) {
        return;
    }

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        FTCommon::msg(this, tr("Failed to open data file."));
        return;
    }

    QString currentText = ui->comboBox->currentText();
    ui->comboBox->clear();
    ui->comboBox->setEditText(currentText);

    QXmlStreamReader reader(&file);
    while (!reader.atEnd()) {
        if (reader.isStartElement() && reader.name() == "Entry") {
            QString title = reader.attributes().value("title").toString();
            if (!title.isEmpty() && ui->comboBox->findText(title) == -1) {
                ui->comboBox->addItem(title);
            }
        }
        reader.readNext();
    }

    file.close();

    if (ui->comboBox->count() > 0) {
        ui->comboBox->setCurrentIndex(0);
    }
}

void Compare::Search()
{
    auto key = ui->edSearch->text().trimmed();
    if (key.isEmpty()) {
        return;
    }

    key = key.toUpper();
    QVector<CompareItem> result;
    for (const auto& item : items_) {
        auto baseNameU = item.baseName.toUpper();
        auto localDirU = item.localDir.toUpper();
        auto remoteDirU = item.remoteDir.toUpper();

        if (baseNameU.contains(key) || localDirU.contains(key) || remoteDirU.contains(key)) {
            result.push_back(item);
        }
    }
    SetResult(result);
    isResource_ = false;
    ui->tableWidget->setIsResource(isResource_);
}

void Compare::Reset()
{
    SetResult(items_);
    isResource_ = true;
    ui->tableWidget->setIsResource(isResource_);
}

void Compare::SetResult(const QVector<CompareItem>& items)
{
    ui->tableWidget->setRowCount(0);
    for (const auto& item : items) {
        int row = ui->tableWidget->rowCount();
        ui->tableWidget->insertRow(row);
        ui->tableWidget->setItem(row, 0, new QTableWidgetItem(item.baseName));
        ui->tableWidget->setItem(row, 1, new QTableWidgetItem(item.localDir));
        ui->tableWidget->setItem(row, 2, new QTableWidgetItem(item.remoteDir));
    }
}

void Compare::FilterFiles(bool isUpload)
{
    QDialog dialog(this);
    QString title = QString("筛选文件类型(%1)").arg(isUpload ? tr("上传") : tr("下载"));
    dialog.setWindowTitle(title);
    dialog.resize(400, 300);
    QListWidget listWidget(&dialog);

    listWidget.setSelectionMode(QAbstractItemView::NoSelection);
    QListWidgetItem* allItem = new QListWidgetItem("*(ALL)");
    allItem->setData(Qt::UserRole, "*ALL");
    allItem->setCheckState(curSelectTypes_.contains("*") ? Qt::Checked : Qt::Unchecked);
    listWidget.addItem(allItem);

    std::map<QString, int> typeCounts;
    int rows = ui->tableWidget->rowCount();
    for (int i = 0; i < rows; ++i) {
        QString ext = ui->tableWidget->item(i, 0)->text().split(".").last().toLower();
        if (typeCounts.count(ext) < 1) {
            QListWidgetItem* item = new QListWidgetItem(ext);
            item->setData(Qt::UserRole, ext);
            item->setCheckState(curSelectTypes_.contains(ext) ? Qt::Checked : Qt::Unchecked);
            listWidget.addItem(item);
            typeCounts[ext] = 1;
        }
    }

    QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
    connect(&buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
    connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);

    QVBoxLayout layout(&dialog);
    layout.addWidget(&listWidget);
    layout.addWidget(&buttons);
    dialog.setLayout(&layout);

    if (dialog.exec() == QDialog::Accepted) {
        QVector<QString> selectedTypes;
        for (int i = 0; i < listWidget.count(); ++i) {
            QListWidgetItem* item = listWidget.item(i);
            if (item->checkState() == Qt::Checked) {
                selectedTypes << item->data(Qt::UserRole).toString();
            }
        }
        curSelectTypes_.clear();
        for (int i = 0; i < selectedTypes.count(); ++i) {
            curSelectTypes_.insert(selectedTypes[i]);
        }
        if (isUpload) {
            TransToRight(true);
        } else {
            TransToLeft(true);
        }
    }
}

void Compare::TransToLeft(bool useSelectTypes)
{
    QVector<TransTask> tasks;

    auto pushTask = [&](const QString& localPath, const QString& remotePath) {
        TransTask task;
        task.taskUUID = Util::UUID();
        task.isUpload = false;
        task.localId = GlobalData::Ins()->GetLocalID();
        task.localPath = localPath;
        task.remoteId = GlobalData::Ins()->GetRemoteID();
        task.remotePath = remotePath;
        tasks.push_back(task);
    };

    if (useSelectTypes) {
        for (int i = 0; i < ui->tableWidget->rowCount(); ++i) {
            QString ext = ui->tableWidget->item(i, 0)->text().split(".").last().toLower();
            if (curSelectTypes_.contains(ext) || curSelectTypes_.contains("*ALL")) {
                const QTableWidgetItem* itemF = ui->tableWidget->item(i, 1);
                const QTableWidgetItem* itemT = ui->tableWidget->item(i, 2);
                pushTask(itemT->text(), Util::Join(itemF->text(), ui->tableWidget->item(i, 0)->text()));
            }
        }
        if (tasks.size() > 0) {
            emit sigTasks(tasks);
        }
    } else {
        QModelIndexList indexList = ui->tableWidget->selectionModel()->selectedRows();
        if (indexList.size() < 1) {
            QMessageBox::information(this, tr("提示"), tr("请选择要下载的文件。"));
            return;
        }
        for (int i = 0; i < indexList.size(); ++i) {
            const QTableWidgetItem* itemF = ui->tableWidget->item(indexList[i].row(), 2);
            const QTableWidgetItem* itemT = ui->tableWidget->item(indexList[i].row(), 1);
            pushTask(itemT->text(), Util::Join(itemF->text(), ui->tableWidget->item(indexList[i].row(), 0)->text()));
        }
        if (tasks.size() > 0) {
            emit sigTasks(tasks);
        }
    }
}

void Compare::TransToRight(bool useSelectTypes)
{
    QVector<TransTask> tasks;

    auto pushTask = [&](const QString& localPath, const QString& remotePath) {
        TransTask task;
        task.taskUUID = Util::UUID();
        task.isUpload = true;
        task.localId = GlobalData::Ins()->GetLocalID();
        task.localPath = localPath;
        task.remoteId = GlobalData::Ins()->GetRemoteID();
        task.remotePath = remotePath;
        tasks.push_back(task);
    };

    if (useSelectTypes) {
        for (int i = 0; i < ui->tableWidget->rowCount(); ++i) {
            QString ext = ui->tableWidget->item(i, 0)->text().split(".").last().toLower();
            if (curSelectTypes_.contains(ext) || curSelectTypes_.contains("*ALL")) {
                const QTableWidgetItem* itemF = ui->tableWidget->item(i, 1);
                const QTableWidgetItem* itemT = ui->tableWidget->item(i, 2);
                pushTask(Util::Join(itemF->text(), ui->tableWidget->item(i, 0)->text()), itemT->text());
            }
        }
        if (tasks.size() > 0) {
            emit sigTasks(tasks);
        }
    } else {
        QModelIndexList indexList = ui->tableWidget->selectionModel()->selectedRows();
        if (indexList.size() < 1) {
            QMessageBox::information(this, tr("提示"), tr("请选择要上传的文件。"));
            return;
        }
        for (int i = 0; i < indexList.size(); ++i) {
            const QTableWidgetItem* itemF = ui->tableWidget->item(indexList[i].row(), 1);
            const QTableWidgetItem* itemT = ui->tableWidget->item(indexList[i].row(), 2);
            pushTask(Util::Join(itemF->text(), ui->tableWidget->item(indexList[i].row(), 0)->text()), itemT->text());
        }
        if (tasks.size() > 0) {
            emit sigTasks(tasks);
        }
    }
}

void Compare::deleteSelectedRows()
{
    auto r = FTCommon::affirm(this, tr("确认"), tr("删除选中的行？"));
    if (!r) {
        return;
    }
    QList<int> rowsToDelete;
    for (QTableWidgetItem* item : ui->tableWidget->selectedItems()) {
        int row = item->row();
        if (!rowsToDelete.contains(row)) {
            rowsToDelete.append(row);
        }
    }
    std::sort(rowsToDelete.begin(), rowsToDelete.end(), std::greater<int>());
    for (int row : rowsToDelete) {
        ui->tableWidget->removeRow(row);
    }
}