#include "statuswidget.h"
#include "ui_statuswidget.h"

#include "models/patchlist.h"

#include "widgets/mainwindow.h"

#include "constants.h"

#include <QDesktopServices>
#include <QUrl>
#include <QDebug>
#include <QMessageBox>

StatusWidget::StatusWidget(PatchList *legacy_patches, QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::StatusWidget)
    , legacy_patches_(legacy_patches)
{

    ui->setupUi(this);
    last_progress_update_time.start();

    connect(ui->weekly_code_widget, &WeeklyCodeWidget::showCompletedTooltip, this, &StatusWidget::setToolTipToWeeklyCodeComplete);
    connect(ui->weekly_code_widget, &WeeklyCodeWidget::showHelpTooltip, this, &StatusWidget::setToolTipToWeeklyCodeHelp);
    connect(ui->weekly_code_widget, &WeeklyCodeWidget::showNoTooltip, this, &StatusWidget::resetToolTip);

    connect(ui->news_list, &NewsListWidget::showHelpToolTip, this, &StatusWidget::setToolTipToNewsHelp);
    connect(ui->news_list, &NewsListWidget::showNoToolTip, this, &StatusWidget::resetToolTip);

    connect(ui->server_status_widget, &ServerStatusWidget::updateServersTooltip, ui->server_status_tooltip, &QLabel::setText);
    connect(ui->server_status_widget, &ServerStatusWidget::showServersTooltip, this, &StatusWidget::setToolTipToServersStatus);
    connect(ui->server_status_widget, &ServerStatusWidget::showNoTooltip, this, &StatusWidget::resetToolTip);

    tooltip_effects[ui->news_tooltip->objectName()] = new QGraphicsOpacityEffect(ui->news_tooltip);
    tooltip_effects[ui->weekly_code_tooltip_1->objectName()] = new QGraphicsOpacityEffect(ui->weekly_code_tooltip_1);
    tooltip_effects[ui->weekly_code_tooltip_2->objectName()] = new QGraphicsOpacityEffect(ui->weekly_code_tooltip_2);
    tooltip_effects[ui->patches_status->objectName()] = new QGraphicsOpacityEffect(ui->patches_status);
    tooltip_effects[ui->server_status_tooltip->objectName()] = new QGraphicsOpacityEffect(ui->server_status_tooltip);

    tooltip_animations[ui->news_tooltip->objectName()] = new QPropertyAnimation(tooltip_effects[ui->news_tooltip->objectName()], "opacity");
    tooltip_animations[ui->weekly_code_tooltip_1->objectName()] = new QPropertyAnimation(tooltip_effects[ui->weekly_code_tooltip_1->objectName()], "opacity");
    tooltip_animations[ui->weekly_code_tooltip_2->objectName()] = new QPropertyAnimation(tooltip_effects[ui->weekly_code_tooltip_2->objectName()], "opacity");
    tooltip_animations[ui->patches_status->objectName()] = new QPropertyAnimation(tooltip_effects[ui->patches_status->objectName()], "opacity");
    tooltip_animations[ui->server_status_tooltip->objectName()] = new QPropertyAnimation(tooltip_effects[ui->server_status_tooltip->objectName()], "opacity");

    ui->news_tooltip->setGraphicsEffect(tooltip_effects[ui->news_tooltip->objectName()]);
    ui->weekly_code_tooltip_1->setGraphicsEffect(tooltip_effects[ui->weekly_code_tooltip_1->objectName()]);
    ui->weekly_code_tooltip_2->setGraphicsEffect(tooltip_effects[ui->weekly_code_tooltip_2->objectName()]);
    ui->patches_status->setGraphicsEffect(tooltip_effects[ui->patches_status->objectName()]);
    ui->server_status_tooltip->setGraphicsEffect(tooltip_effects[ui->server_status_tooltip->objectName()]);

    foreach (QPropertyAnimation* animation, tooltip_animations) {
        animation->setDuration(350);
        animation->setStartValue(0);
        animation->setEndValue(1);
        animation->setDirection(QAbstractAnimation::Forward);
    }

    foreach (QGraphicsOpacityEffect* effect, tooltip_effects) {
        effect->setOpacity(0);
    }

    active_tooltip = nullptr;
    resetToolTip();

    connect(legacy_patches_, &PatchList::downloadTotalStatusChanged, this, &StatusWidget::onDownloadTotalStatusChanged);
    connect(legacy_patches_, &PatchList::installTotalStatusChanged, this, &StatusWidget::onInstallTotalStatusChanged);
    connect(legacy_patches_, &PatchList::patchOperationsStarted, this, &StatusWidget::onPatchOperationsStarted);
    connect(legacy_patches_, &PatchList::patchOperationsFinished, this, &StatusWidget::onPatchOperationsFinished);

    foreach (Patch* patch, legacy_patches_->getPatchList()) {
        connect(patch, &Patch::downloadStatusChanged, this, &StatusWidget::onPatchDownloadStatusChanged);
        connect(patch, &Patch::installStatusChanged, this, &StatusWidget::onPatchInstallStatusChanged);
        connect(patch, &Patch::operationFinished, this, &StatusWidget::onPatchOperationFinished);
        connect(patch, &Patch::operationStarted, this, &StatusWidget::onPatchOperationStarted);
    }
}

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

void StatusWidget::updateFontsSizes()
{
    ui->progress_label->setFont(crimson_10pt);
    ui->game_button->setFont(trajan_11pt);
    ui->news_label->setFont(trajan_10pt);

    ui->graphicspatch_label->setFont(crimson_11pt);
    ui->graphicspatch_status->setFont(crimson_11pt);
    ui->soundspatch_label->setFont(crimson_11pt);
    ui->soundspatch_status->setFont(crimson_11pt);
    ui->textspatch_label->setFont(crimson_11pt);
    ui->textspatch_status->setFont(crimson_11pt);
    ui->videospatch_label->setFont(crimson_11pt);
    ui->videospatch_status->setFont(crimson_11pt);

    ui->news_tooltip->setFont(garamond_11pt);
    ui->weekly_code_tooltip_1->setFont(garamond_11pt);
    ui->weekly_code_tooltip_2->setFont(garamond_11pt);
    ui->server_status_tooltip->setFont(garamond_11pt);
}

void StatusWidget::resizeEvent(QResizeEvent *)
{
    double coefficient = window_width / default_window_width;
    ui->game_button->move(QPoint(820, 460) * coefficient);
    ui->game_button->resize(QSize(150, 60) * coefficient);
    ui->progressBar->move(QPoint(320, 480) * coefficient);
    ui->progressBar->resize(QSize(470, 40) * coefficient);
    ui->progress_label->move(QPoint(330, 390) * coefficient);
    ui->progress_label->resize(QSize(380, 90) * coefficient);
    ui->news_label->move(QPoint(45, 33)* coefficient);
    ui->news_label->resize(QSize(180, 21) * coefficient);
    ui->news_scroll_area->move(QPoint(40, 75) * coefficient);
    ui->news_scroll_area->resize(QSize(240, 440) * coefficient);
    ui->server_status_widget->move(QPoint(820, 90) * coefficient);
    ui->server_status_widget->resize(QSize(155, 320) * coefficient);
    ui->weekly_code_widget->move(QPoint(810, 13) * coefficient);
    ui->weekly_code_widget->resize(QSize(173, 57) * coefficient);
    ui->galadriel_widget->move(QPoint(320, 20) * coefficient);
    ui->galadriel_widget->resize(QSize(531, 461) * coefficient);

    ui->news_tooltip->move(QPoint(38, 13) * coefficient);
    ui->news_tooltip->resize(QSize(365, 114) * coefficient);
    ui->weekly_code_tooltip_1->move(QPoint(38, 13) * coefficient);
    ui->weekly_code_tooltip_1->resize(QSize(365, 114) * coefficient);
    ui->weekly_code_tooltip_2->move(QPoint(38, 13) * coefficient);
    ui->weekly_code_tooltip_2->resize(QSize(365, 114) * coefficient);
    ui->server_status_tooltip->move(QPoint(38, 13) * coefficient);
    ui->server_status_tooltip->resize(QSize(365, 114) * coefficient);

    ui->patches_status->move(QPoint(38, 13) * coefficient);
    ui->patches_status->resize(QSize(385, 114) * coefficient);

    updateFontsSizes();
}

void StatusWidget::setToolTipToWeeklyCodeHelp()
{
    fadeBetweenToolTips(ui->weekly_code_tooltip_1);
}

void StatusWidget::setToolTipToWeeklyCodeComplete()
{
    fadeBetweenToolTips(ui->weekly_code_tooltip_2);
}

void StatusWidget::setToolTipToNewsHelp()
{
    fadeBetweenToolTips(ui->news_tooltip);
}

void StatusWidget::setToolTipToServersStatus()
{
    fadeBetweenToolTips(ui->server_status_tooltip);
}

void StatusWidget::resetToolTip()
{
    fadeBetweenToolTips(ui->patches_status);
}

void StatusWidget::fadeBetweenToolTips(QWidget* next_tooltip)
{
    if (active_tooltip) {
        QPropertyAnimation* active_tooltip_anim = tooltip_animations[active_tooltip->objectName()];

        active_tooltip_anim->setDirection(QAbstractAnimation::Backward);

        if (active_tooltip_anim->state() == QAbstractAnimation::Stopped)
            active_tooltip_anim->start();
    }

    QPropertyAnimation* next_active_tooltip_anim = tooltip_animations[next_tooltip->objectName()];
    next_active_tooltip_anim->setDirection(QAbstractAnimation::Forward);

    if (next_active_tooltip_anim->state() == QAbstractAnimation::Stopped)
        next_active_tooltip_anim->start();

    active_tooltip = next_tooltip;
}

void StatusWidget::onPatchOperationsStarted()
{
    ui->game_button->setEnabled(false);
    ui->progress_label->setText("Выполение операций....");
    ui->progressBar->setValue(0);
}

void StatusWidget::onPatchOperationsFinished()
{
    ui->game_button->setEnabled(true);
    ui->progress_label->setText("Все операции завершены.");
    ui->progressBar->setValue(100);
}

void StatusWidget::onDownloadTotalStatusChanged(Downloader::Status status)
{
    last_download_status_ = status;
    updateStatusBar();
//        qDebug() << "Download total status: \n" <<
//                    "    cur_speed = " << Downloader::getSpeedFormatted(status.current_speed) << "\n" <<
//                    "    avg_speed = " << Downloader::getSpeedFormatted(status.average_speed) << "\n" <<
//                    "    percent = " << status.percent << "\n" <<
//                    "    total size = " << Downloader::getSizeFormatted(status.total_bytes) << "\n" <<
//                    "    downloaded size = " << Downloader::getSizeFormatted(status.downloaded_bytes) << "\n" <<
//                    "    elapsed time = " << status.elapsed_time << "\n\n";

}

void StatusWidget::onInstallTotalStatusChanged(Patch::InstallationStatus status)
{
    last_install_status_ = status;
    updateStatusBar();
}

void StatusWidget::onPatchOperationStarted(QString operation_name, Patch *patch)
{
    QLabel* patch_status_label = findChild<QLabel*>(patch->getPatchName().toLower() + "_status");
    if (!patch_status_label) {
        qDebug() << "Cannot find status label for patch " << patch->getPatchName();
        return;
    }

    QString text = "";
    if (operation_name == "checkForUpdates") {
        text = "Поиск и проверка обновлений...";
    }
    if (operation_name == "download") {
        text = "Проверка файлов данных...";
    }
    if (operation_name == "install") {
        text = "Ожидание начала установки...";
    }
    if (operation_name == "apply") {
        text = "Ожидание начала применения...";
    }

    patch_status_label->setText(text);
}

void StatusWidget::onPatchOperationFinished(QString operation_name, Patch *patch, bool result)
{
    QLabel* patch_status_label = findChild<QLabel*>(patch->getPatchName().toLower() + "_status");
    if (!patch_status_label) {
        qDebug() << "Cannot find status label for patch " << patch->getPatchName();
        return;
    }

    if (result) {
        patch_status_label->setText("Все операции завершены");
        QString install_date;
        if (!(install_date = Settings::getValue("UpdateDates/" + patch->getPatchName()).toString()).isEmpty()) {
            patch_status_label->setText("Патч версии от " + install_date);
        }
    } else {
        patch_status_label->setText("Операция завершилась с ошибкой");
    }
}

void StatusWidget::onPatchDownloadStatusChanged(Patch *patch, Downloader::Status status)
{
    QString label_name = patch->getPatchName().toLower() + "_status";
    QLabel *label = findChild<QLabel*>(label_name);
    if (!label) {
        qDebug() << "Error, cannot find child of StatusWidget with name " + label_name;
        return;
    }

    label->setText("Загрузка " + QString::number(status.percent, 'f', 1) + "% (" + Downloader::getSizeFormatted(status.downloaded_bytes) + " / "
                   + Downloader::getSizeFormatted(status.total_bytes) + ")");
}

void StatusWidget::onPatchInstallStatusChanged(Patch *patch, Patch::InstallationStatus status)
{
    QString label_name = patch->getPatchName().toLower() + "_status";
    QLabel *label = findChild<QLabel*>(label_name);
    if (!label) {
        qDebug() << "Error, cannot find child of StatusWidget with name " + label_name;
        return;
    }

    if (status.process == Patch::CurrentProcess::E_INSTALL) {
        label->setText("Установка (" + QString::number(status.current_part) + " из " + QString::number(status.total_parts) + ") " + QString::number(status.percent, 'f', 1));
    }
}

void StatusWidget::updateStatusBar()
{
    if (last_progress_update_time.elapsed() > 1000) {
        QString text = "Выполнение операций...";
        if (last_download_status_.running) {
            text += "\nЗагрузка данных: " + QString::number(last_download_status_.percent, 'f', 1) + "% ("
                    + Downloader::getSizeFormatted(last_download_status_.downloaded_bytes) + "/"
                    + Downloader::getSizeFormatted(last_download_status_.total_bytes) + ", "
                    + Downloader::getSpeedFormatted(last_download_status_.current_speed) + ")\n"
                    + "Осталось примерно: " + Downloader::getElapsedTimeFormatted(last_download_status_.elapsed_time);
        }

        if (last_install_status_.process != Patch::CurrentProcess::E_FINISHED) {
            text += "\nПрименение патчей: " + QString::number(last_install_status_.percent + 100.0 * (last_install_status_.current_part - 1) / (100 * last_install_status_.total_parts), 'f', 1) + "%";
        }

        ui->progress_label->setText(text);
        ui->progressBar->setValue(last_download_status_.percent * 0.85 + last_install_status_.percent * 0.15);
        last_progress_update_time.restart();
    }
}


