#include "ui_settingswidget.h"

#include "models/settings.h"
#include "models/patchlist.h"

#include "widgets/settingswidget.h"
#include "widgets/mainwindow.h"

#include "constants.h"

#include <QDebug>
#include <QScrollBar>
#include <QFileDialog>
#include <QMetaObject>
#include <QMessageBox>

using namespace SettingsWidgetPrivate;

SettingsWidget::SettingsWidget(PatchList *legacy_patches, QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::SettingsWidget)
    , legacy_patches_(legacy_patches)
{
    settings_changed_ = false;

    ui->setupUi(this);

    combobox_scrolling_disabler = new ComboboxScrollingDisabler();
    scroller = new SettingsTabsScroller({ui->sub_entry_1,
                                         ui->sub_entry_2,
                                         ui->sub_entry_3,
                                         ui->sub_entry_4
                                        },
                                        ui->content_scroll_area);

    ui->lotro_base_language_combobox->installEventFilter(combobox_scrolling_disabler);
    ui->interface_scale_combobox->installEventFilter(combobox_scrolling_disabler);
//    ui->content_scroll_area->verticalScrollBar()->installEventFilter(scroller);

    ui->patch_installing_label->hide();
    connect(legacy_patches, &PatchList::patchOperationsStarted, this, &SettingsWidget::onPatchTotalOperationsStarted);
    connect(legacy_patches, &PatchList::patchOperationsFinished, this, &SettingsWidget::onPatchTotalOperationsFinished);
    connect(legacy_patches, &PatchList::backupSettingsInfoChanged, this, &SettingsWidget::onBackupSettingsInfoChanged);
    connect(legacy_patches->getManager(), &LotroDatManager::statusChanged, this, &SettingsWidget::onLotroManagerProcessChanged);

    ui->apply_changes_button->hide();
    ui->apply_changes_label->hide();
    ui->patch_installing_label->hide();
    settings_backup_ = Settings::createSettingsBackup();
    setActualParametersValues();
}

SettingsWidget::~SettingsWidget()
{
    delete combobox_scrolling_disabler;
    delete scroller;
    delete ui;
}

void SettingsWidget::setActualParametersValues()
{
    QString game_path = Settings::getValue("Lotro/game_path").toString();
    if (game_path == "none") {
        game_path = "Путь к файлам игры не выбран";
    }
    ui->game_folder_path->setText(game_path);


    QString original_locale = Settings::getValue("Lotro/original_locale").toString();
    int index = 0;

    if (original_locale == "English")
        index = 0;
    if (original_locale == "DE")
        index = 1;
    if (original_locale == "FR")
        index = 2;
    ui->lotro_base_language_combobox->setCurrentIndex(index);

    ui->skiprawdownload_checkbox->setChecked(Settings::getValue("Lotro/skip_raw_download").toBool());
    ui->nosplashscreen_checkbox->setChecked(Settings::getValue("Lotro/no_splash_screen").toBool());

    QString backup_status = Settings::getValue("Backup/installed").toBool() ? "Активна" : "Отсутствует";
    ui->backup_status_value->setText(backup_status);
    ui->backup_path_value->setText(QApplication::applicationDirPath() + Settings::getValue("Backup/path").toString());
    QString backup_creation_time = Settings::getValue("Backup/creation_time").toString();
    if (backup_creation_time == "none")
        backup_creation_time = "-";
    ui->backup_creation_time_value->setText(backup_creation_time);

    ui->patch_texts_checkbox->setChecked(Settings::getValue("Components/texts_main").toBool());
    ui->patch_items_checkbox->setChecked(Settings::getValue("Components/texts_items").toBool());
    ui->patch_emotes_checkbox->setChecked(Settings::getValue("Components/texts_emotes").toBool());
    ui->patch_maps_checkbox->setChecked(Settings::getValue("Components/maps").toBool());
    ui->patch_loadscreens_checkbox->setChecked(Settings::getValue("Components/loadscreens").toBool());
    ui->patch_textures_checkbox->setChecked(Settings::getValue("Components/textures").toBool());
    ui->patch_sounds_checkbox->setChecked(Settings::getValue("Components/sounds").toBool());
    ui->patch_video_checkbox->setChecked(Settings::getValue("Components/videos").toBool());
    ui->micropatch_checkbox->setChecked(Settings::getValue("Components/micropatch").toBool());

    int interface_scale = Settings::getValue("General/UI_scale").toInt();

    int interface_scale_combobox_index = 0;
    if (interface_scale == 50)
        interface_scale_combobox_index = 0;
    if (interface_scale == 75)
        interface_scale_combobox_index = 1;
    if (interface_scale == 100)
        interface_scale_combobox_index = 2;
    if (interface_scale == 125)
        interface_scale_combobox_index = 3;
    if (interface_scale == 150)
        interface_scale_combobox_index = 4;
    if (interface_scale == 175)
        interface_scale_combobox_index = 5;
    if (interface_scale == 200)
        interface_scale_combobox_index = 6;

    ui->interface_scale_combobox->setCurrentIndex(interface_scale_combobox_index);
}

void SettingsWidget::updateFontsSizes()
{
    ui->frame_title->setFont(trajan_10pt);
    ui->group_label_1->setFont(trajan_9pt);
    ui->group_label_2->setFont(trajan_9pt);
    ui->group_label_3->setFont(trajan_9pt);
    ui->group_label_4->setFont(trajan_9pt);

    ui->patch_installing_label->setFont(crimson_12pt);
    ui->apply_changes_button->setFont(trajan_10pt);

    ui->sub_entry_1_title->setFont(garamond_11pt);
    ui->sub_entry_2_title->setFont(garamond_11pt);
    ui->sub_entry_3_title->setFont(garamond_11pt);
    ui->sub_entry_4_title->setFont(garamond_11pt);

    ui->backup_create_button->setFont(trajan_8pt);
    ui->backup_restore_button->setFont(trajan_8pt);
    ui->backup_remove_button->setFont(trajan_8pt);

    ui->game_folder_label->setFont(crimson_11pt);
    ui->game_folder_path->setFont(crimson_11pt);
    ui->lotro_base_language_label->setFont(crimson_11pt);
    ui->lotro_base_language_combobox->setFont(crimson_11pt);
    ui->lotro_base_language_combobox->insertItem(ui->lotro_base_language_combobox->count(), ""); // is needed to invoke elements resize
    ui->lotro_base_language_combobox->removeItem(ui->lotro_base_language_combobox->count() - 1);
    ui->skiprawdownload_checkbox->setFont(crimson_11pt);
    ui->nosplashscreen_checkbox->setFont(crimson_11pt);

    ui->backup_status_label->setFont(crimson_11pt);
    ui->backup_status_value->setFont(crimson_11pt);
    ui->backup_creation_time_label->setFont(crimson_11pt);
    ui->backup_creation_time_value->setFont(crimson_11pt);
    ui->backup_path_label->setFont(crimson_11pt);
    ui->backup_path_value->setFont(crimson_11pt);

    ui->patch_emotes_checkbox->setFont(crimson_11pt);
    ui->patch_items_checkbox->setFont(crimson_11pt);
    ui->patch_loadscreens_checkbox->setFont(crimson_11pt);
    ui->patch_maps_checkbox->setFont(crimson_11pt);
    ui->patch_sounds_checkbox->setFont(crimson_11pt);
    ui->patch_textures_checkbox->setFont(crimson_11pt);
    ui->patch_video_checkbox->setFont(crimson_11pt);
    ui->patch_texts_checkbox->setFont(crimson_11pt);

    ui->micropatch_checkbox->setFont(crimson_11pt);
    ui->interface_scale_label->setFont(crimson_11pt);
    ui->interface_scale_combobox->setFont(crimson_11pt);
    ui->interface_scale_combobox->insertItem(ui->interface_scale_combobox->count(), "250%"); // is needed to invoke elements resize
    ui->interface_scale_combobox->removeItem(ui->interface_scale_combobox->count() - 1);

    ui->texts_block_label->setFont(crimson_12pt);
    ui->graphics_block_label->setFont(crimson_12pt);
    ui->sounds_block_label->setFont(crimson_12pt);
}

void SettingsWidget::resizeEvent(QResizeEvent *)
{
    updateFontsSizes();
    double coefficient = window_width / default_window_width;

    ui->frame_title->move(QPoint(45, 33) * coefficient);
    ui->frame_title->resize(QSize(201, 21) * coefficient);
    ui->checkpoints_list->move(QPoint(25, 70) * coefficient);
    ui->checkpoints_list->resize(QSize(265, 451) * coefficient);

    ui->content_scroll_area->move(QPoint(310, 0) * coefficient);
    ui->content_scroll_area->resize(QSize(671, 521) * coefficient);
    ui->content_widget->setMinimumWidth(650 * coefficient);

    ui->change_folder_button->setMinimumSize(QSize(36, 32) * coefficient);

    ui->patch_texts_icon->setMinimumSize(QSize(80, 80) * coefficient);
    ui->patch_graphics_icon->setMinimumSize(QSize(80, 80) * coefficient);
    ui->patch_sounds_icon->setMinimumSize(QSize(80, 80) * coefficient);
    ui->apply_changes_button->setMinimumSize(QSize(160, 60) * coefficient);
}

void SettingsWidget::onLotroManagerProcessChanged(LotroDatManager::Status status)
{
    if (status.status != LOTRO_DAT::DatStatus::E_BACKUP_CREATING &&
            status.status != LOTRO_DAT::DatStatus::E_BACKUP_REMOVING &&
            status.status != LOTRO_DAT::DatStatus::E_BACKUP_RESTORING) {
        return;
    }

    QString operation;
    if (status.status == LOTRO_DAT::DatStatus::E_BACKUP_CREATING) {
        operation = "Создание копии";
    }
    if (status.status == LOTRO_DAT::DatStatus::E_BACKUP_REMOVING) {
        operation = "Удаление копии";
    }
    if (status.status == LOTRO_DAT::DatStatus::E_BACKUP_RESTORING) {
        operation = "Восстановление данных";
    }

    operation = operation + " " + QString::number(status.percentage, 'f', 1) + "%";
    ui->backup_status_value->setText(operation);
}

void SettingsWidget::onBackupSettingsInfoChanged()
{
    settings_backup_["Backup/installed"] = Settings::getValue("Backup/installed");
    settings_backup_["Backup/path"] = Settings::getValue("Backup/path");
    settings_backup_["Backup/creation_time"] = Settings::getValue("Backup/creation_time");

    QString backup_status = Settings::getValue("Backup/installed").toBool() ? "Активна" : "Отсутствует";
    ui->backup_status_value->setText(backup_status);

    ui->backup_path_value->setText(QApplication::applicationDirPath() + Settings::getValue("Backup/path").toString());

    QString backup_creation_time = Settings::getValue("Backup/creation_time").toString();
    if (backup_creation_time == "none")
        backup_creation_time = "-";
    ui->backup_creation_time_value->setText(backup_creation_time);
}

void SettingsWidget::processParameterChange() {
    if (!settings_changed_) {
        settings_changed_ = true;
        emit SettingsChanged();
        ui->apply_changes_label->show();
        ui->apply_changes_button->show();
    }
}

void SettingsWidget::checkIfParametersWereReset() {
    if (settings_changed_ && settings_backup_ == Settings::createSettingsBackup()) {
        settings_changed_ = false;
        emit SettingsReset();
        ui->apply_changes_label->hide();
        ui->apply_changes_button->hide();
    }
}

void SettingsWidget::on_change_folder_button_clicked()
{
    QStringList known_paths = FileSystem::recognizeRegistryLotroPath();
    QString template_path = known_paths.empty() ? "" : known_paths[0];
    QString str = QFileDialog::getOpenFileName(0, "Расположение игры", template_path, "LotroLauncher.exe");

    if (str.isEmpty()) {
        return;
    }

    QString game_folder= str.replace("/LotroLauncher.exe", "").replace("\\", "/").replace("//", "/") + "/";

    if (settings_backup_["Lotro/game_path"].toString() == game_folder) {
        return;
    }

    processParameterChange();
    settings_backup_["Lotro/game_path"] = game_folder;
    ui->game_folder_path->setText(game_folder);
    checkIfParametersWereReset();
}

void SettingsWidget::on_lotro_base_language_combobox_currentIndexChanged(int index)
{
    QString value = "English";

    if (index == 0)
        value = "English";
    if (index == 1)
        value = "DE";
    if (index == 2)
        value = "FR";

    if (settings_backup_["Lotro/original_locale"].toString() == value) {
        return;
    }

    processParameterChange();
    settings_backup_["Lotro/original_locale"] = value;
    checkIfParametersWereReset();
}

void SettingsWidget::on_skiprawdownload_checkbox_stateChanged(int arg1) {
    if (arg1 == Qt::Checked) {
        Settings::setValue("Lotro/skip_raw_download", true);
        settings_backup_["Lotro/skip_raw_download"] = true;
    }
    if (arg1 == Qt::Unchecked) {
        Settings::setValue("Lotro/skip_raw_download", false);
        settings_backup_["Lotro/skip_raw_download"] = false;
    }
}

void SettingsWidget::on_nosplashscreen_checkbox_stateChanged(int arg1)
{
    if (arg1 == Qt::Checked) {
        Settings::setValue("Lotro/no_splash_screen", true);
        settings_backup_["Lotro/no_splash_screen"] = true;
    }
    if (arg1 == Qt::Unchecked) {
        Settings::setValue("Lotro/no_splash_screen", false);
        settings_backup_["Lotro/no_splash_screen"] = false;
    }
}

void SettingsWidget::on_backup_create_button_clicked()
{
    if (settings_changed_) {
        QMessageBox::warning(nullptr, "Невозможно выполнить действие!", "Некоторые настройки были изменены. Чтобы создать резервную копию, примените или отмените изменения!");
        return;
    }

    if (Settings::getValue("Backup/installed").toBool()) {
        int result = QMessageBox::question(nullptr, "Подтвердите действие", "Резервная копия уже существует. Вы хотите перезаписать существующую копию?", QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);
        if (result != QMessageBox::Yes) {
            return;
        }
    }

    QMetaObject::invokeMethod(legacy_patches_, "createBackup", Qt::QueuedConnection);
}

void SettingsWidget::on_backup_restore_button_clicked()
{
    if (!Settings::getValue("Backup/installed").toBool()) {
        QMessageBox::warning(nullptr, "Невозможно выполнить действие.", "Резервная копия не найдена. Создайте резервную копию, чтобы иметь возможность восстановления данных.");
        return;
    }

    if (settings_changed_) {
        QMessageBox::warning(nullptr, "Невозможно выполнить действие.", "Некоторые настройки были изменены. Чтобы восстановить данные из резервной копии, примените или отмените изменения!");
        return;
    }

    QMetaObject::invokeMethod(legacy_patches_, "restoreFromBackup", Qt::QueuedConnection);
}

void SettingsWidget::on_backup_remove_button_clicked()
{
    if (Settings::getValue("Backup/installed").toBool()) {
        int result = QMessageBox::question(nullptr, "Подтвердите действие", "Вы уверены, что хотите удалить существующую резервную копию?", QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);
        if (result != QMessageBox::Yes) {
            return;
        }
    } else {
        QMessageBox::information(nullptr, "Невозможно выполнить действие.", "Удаление невозможно: резервной копии не существует.");
        return;
    }

    QMetaObject::invokeMethod(legacy_patches_, "removeBackup", Qt::QueuedConnection);
}

void SettingsWidget::on_patch_texts_checkbox_clicked()
{
    processParameterChange();
    if (ui->patch_texts_checkbox->isChecked()) {
        settings_backup_["Components/texts_main"] = true;
    } else {
        settings_backup_["Components/texts_main"] = false;
    }
    checkIfParametersWereReset();
}

void SettingsWidget::on_patch_items_checkbox_clicked()
{
    processParameterChange();
    if (ui->patch_items_checkbox->isChecked()) {
        settings_backup_["Components/texts_items"] = true;
    } else {
        settings_backup_["Components/texts_items"] = false;
    }
    checkIfParametersWereReset();
}

void SettingsWidget::on_patch_emotes_checkbox_clicked()
{
    processParameterChange();
    if (ui->patch_emotes_checkbox->isChecked()) {
        settings_backup_["Components/texts_emotes"] = true;
    } else {
        settings_backup_["Components/texts_emotes"] = false;
    }
    checkIfParametersWereReset();
}

void SettingsWidget::on_patch_maps_checkbox_clicked()
{
    processParameterChange();
    if (ui->patch_maps_checkbox->isChecked()) {
        settings_backup_["Components/maps"] = true;
    } else {
        settings_backup_["Components/maps"] = false;
    }
    checkIfParametersWereReset();
}

void SettingsWidget::on_patch_textures_checkbox_clicked()
{
    processParameterChange();
    if (ui->patch_textures_checkbox->isChecked()) {
        settings_backup_["Components/textures"] = true;
    } else {
        settings_backup_["Components/textures"] = false;
    }
    checkIfParametersWereReset();
}

void SettingsWidget::on_patch_loadscreens_checkbox_clicked()
{
    processParameterChange();
    if (ui->patch_loadscreens_checkbox->isChecked()) {
        settings_backup_["Components/loadscreens"] = true;
    } else {
        settings_backup_["Components/loadscreens"] = false;
    }
    checkIfParametersWereReset();

}

void SettingsWidget::on_patch_sounds_checkbox_clicked()
{
    processParameterChange();
    if (ui->patch_sounds_checkbox->isChecked()) {
        settings_backup_["Components/sounds"] = true;
    } else {
        settings_backup_["Components/sounds"] = false;
    }
    checkIfParametersWereReset();
}

void SettingsWidget::on_patch_video_checkbox_clicked()
{
    processParameterChange();
    if (ui->patch_video_checkbox->isChecked()) {
        settings_backup_["Components/videos"] = true;
    } else {
        settings_backup_["Components/videos"] = false;
    }
    checkIfParametersWereReset();
}

void SettingsWidget::on_patch_force_apply_button_clicked()
{
    QMetaObject::invokeMethod(legacy_patches_, "forceInstallPatches");
}

void SettingsWidget::on_micropatch_checkbox_clicked()
{
    processParameterChange();
    if (ui->micropatch_checkbox->isChecked()) {
        settings_backup_["Components/micropatch"] = true;
    } else {
        settings_backup_["Components/micropatch"] = false;
    }
    checkIfParametersWereReset();
}

void SettingsWidget::on_interface_scale_combobox_currentIndexChanged(const QString &arg1)
{
    MainWindow* window = qobject_cast<MainWindow*>(qApp->activeWindow());

    if (!window) {
        ui->interface_scale_combobox->setCurrentText(Settings::getValue("General/UI_scale").toString() + "%");
        qDebug() << "CANNOT FIND MAIN WINDOW!!!";
        return;
    }

    int value = arg1.left(arg1.length() - 1).toInt();
    window->resize(default_window_width * value / 100, default_window_height * value / 100);

    Settings::setValue("General/UI_scale", value);
    settings_backup_["General/UI_scale"] = value;
}

void SettingsWidget::onPatchTotalOperationsStarted()
{
    patch_operations_running_ = true;
    ui->patch_installing_label->show();

    ui->change_folder_button->setEnabled(false);
    ui->lotro_base_language_combobox->setEnabled(false);

    ui->backup_create_button->setEnabled(false);
    ui->backup_restore_button->setEnabled(false);
    ui->backup_remove_button->setEnabled(false);

    ui->patch_texts_checkbox->setEnabled(false);
    ui->patch_items_checkbox->setEnabled(false);
    ui->patch_emotes_checkbox->setEnabled(false);
    ui->patch_maps_checkbox->setEnabled(false);
    ui->patch_textures_checkbox->setEnabled(false);
    ui->patch_loadscreens_checkbox->setEnabled(false);
    ui->patch_sounds_checkbox->setEnabled(false);
    ui->patch_video_checkbox->setEnabled(false);
    ui->patch_force_apply_button->setEnabled(false);
    ui->micropatch_checkbox->setEnabled(false);
}

void SettingsWidget::onPatchTotalOperationsFinished()
{
    patch_operations_running_ = false;
    ui->patch_installing_label->hide();
    settings_backup_ = Settings::createSettingsBackup();

    ui->change_folder_button->setEnabled(true);
    ui->lotro_base_language_combobox->setEnabled(true);

    ui->backup_create_button->setEnabled(true);
    ui->backup_restore_button->setEnabled(true);
    ui->backup_remove_button->setEnabled(true);

    ui->patch_texts_checkbox->setEnabled(true);
    ui->patch_items_checkbox->setEnabled(true);
    ui->patch_emotes_checkbox->setEnabled(true);
    ui->patch_maps_checkbox->setEnabled(true);
    ui->patch_textures_checkbox->setEnabled(true);
    ui->patch_loadscreens_checkbox->setEnabled(true);
    ui->patch_sounds_checkbox->setEnabled(true);
    ui->patch_video_checkbox->setEnabled(true);
    ui->patch_force_apply_button->setEnabled(true);
    ui->micropatch_checkbox->setEnabled(true);
}

void SettingsWidget::on_apply_changes_button_clicked()
{
    Settings::restoreFromSettingsBackup(settings_backup_);
    Settings::updatePatchComponentsDependencies();
    settings_changed_ = false;
    ui->apply_changes_label->hide();
    ui->apply_changes_button->hide();
    emit SettingsApplied();
}

