#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_statusbar_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::patchOperationsStarted, this, &StatusWidget::onPatchTotalOperationsStarted);
    connect(legacy_patches_, &PatchList::patchOperationsFinished, this, &StatusWidget::onPatchTotalOperationsFinished);
    connect(legacy_patches_, &PatchList::progressChanged, this, &StatusWidget::onPatchTotalProgressChanged);

    foreach (Patch* patch, legacy_patches_->getPatchList()) {
        connect(patch, &Patch::progressChanged, this, &StatusWidget::onPatchProgressChanged);
        connect(patch, &Patch::operationStarted, this, &StatusWidget::onPatchOperationStarted);
        connect(patch, &Patch::operationFinished, this, &StatusWidget::onPatchOperationFinished);
    }
}

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::onPatchTotalOperationsStarted()
{
    all_patch_operations_finished_ = false;
    ui->game_button->setEnabled(false);
}

void StatusWidget::onPatchTotalOperationsFinished()
{
    all_patch_operations_finished_ = true;
    ui->game_button->setEnabled(true);

    for (Patch* patch : legacy_patches_->getPatchList()) {
        QString label_name = patch->getPatchName().toLower() + "_status";
        QLabel *label = findChild<QLabel*>(label_name);
        if (!label) {
            return;
        }

        QString install_date;
        if (!(install_date = Settings::getValue("UpdateDates/" + patch->getPatchName()).toString()).isEmpty()) {
            label->setText("Патч версии от " + install_date);
        } else {
            label->setText("Все операции с патчем завершены.");
        }
    }

    ui->progress_label->setText("");
}

void StatusWidget::onPatchOperationStarted(Patch::Operation operation, Patch *patch)
{
    QString label_name = patch->getPatchName().toLower() + "_status";
    QLabel *label = findChild<QLabel*>(label_name);
    patch_operations[patch] = operation;
    if (!label) {
        return;
    }

    switch (operation) {
    case Patch::E_CHECKFORUPDATES:
        label->setText("Проверка наличия обновлений...");
        break;
    case Patch::E_DOWNLOAD:
        label->setText("Подготовка к загрузке данных...");
        break;
    case Patch::E_INSTALL:
        label->setText("Ожидание начала установки...");
        break;
    case Patch::E_ACTIVATE:
        label->setText("Ожидание начала активации...");
    default:
        break;
    }
}

void StatusWidget::onPatchOperationFinished(Patch::Operation operation, Patch *patch)
{
    if (all_patch_operations_finished_) {
        return;
    }

    QString label_name = patch->getPatchName().toLower() + "_status";
    QLabel *label = findChild<QLabel*>(label_name);

    if (!label) {
        return;
    }

    switch (operation) {
    case Patch::E_CHECKFORUPDATES:
        label->setText("Проверка обновлений завершена");
        break;
    case Patch::E_DOWNLOAD:
        label->setText("Загрузка данных завершена");
        break;
    case Patch::E_INSTALL:
        label->setText("Установка патча завершена");
        break;
    case Patch::E_ACTIVATE:
        label->setText("Активация патча завершена");
    default:
        break;
    }
}

void StatusWidget::onPatchTotalProgressChanged(Patch::OperationProgress operation_progress)
{
    updateStatusBar(operation_progress);
}

void StatusWidget::onPatchProgressChanged(Patch::OperationProgress progress, Patch *patch)
{
    QString label_name = patch->getPatchName().toLower() + "_status";
    QLabel *label = findChild<QLabel*>(label_name);
    if (!label) {
        return;
    }

    switch (patch_operations[patch]) {
    case Patch::E_CHECKFORUPDATES:
        label->setText("Проверка наличия обновлений...");
        break;
    case Patch::E_DOWNLOAD:
        label->setText("Загрузка... " + QString::number(progress.getDownloadPercent(), 'f', 1)
                       + "% (" + Downloader::getSizeFormatted(progress.download_finished_bytes)
                       + "/" + Downloader::getSizeFormatted(progress.download_total_bytes) + ")");
        break;
    case Patch::E_INSTALL:
        label->setText("Установка... " + QString::number(progress.getInstallPercent(), 'f', 2)
                       + "% (" + QString::number(progress.install_finished_parts) + "/" + QString::number(progress.install_total_parts) + ")");
        break;
    case Patch::E_ACTIVATE:
        label->setText("Активация... " + QString::number(progress.getInstallPercent(), 'f', 2)
                       + "% (" + QString::number(progress.install_finished_parts) + "/" + QString::number(progress.install_total_parts) + ")");
    default:
        break;
    }
}

void StatusWidget::updateStatusBar(Patch::OperationProgress progress)
{
    if (last_statusbar_update_time_.elapsed() > 500) {
        QString text = "Выполнение операций...";
        if (progress.download_total_bytes != 0) {
            text += "\nЗагрузка данных: " + QString::number(progress.getDownloadPercent(), 'f', 1) + "% ("
                    + Downloader::getSizeFormatted(progress.download_finished_bytes) + "/"
                    + Downloader::getSizeFormatted(progress.download_total_bytes) + ", "
                    + Downloader::getSpeedFormatted(progress.download_speed) + ")\n"
                    + "До конца загрузки: " + Downloader::getElapsedTimeFormatted(progress.download_elapsed_time);
        }

        if (progress.install_total_parts != 0) {
            text += "\nПрименение патчей: " + QString::number(progress.getInstallPercent()) + "% "
                    + "(часть " + QString::number(progress.install_finished_parts + 1) + " из " + QString::number(progress.install_total_parts);
        }

        ui->progress_label->setText(text);
        last_statusbar_update_time_.restart();
    }
}


