#include "ui/hotseat_recruitment/recruitmentscene.h"
#include "ui/dialog_form/dialogform.h"
#include "ui_recruitmentscene.h"

#include "gui/guiscenemanager.h"
#include "gui/scene.h"

#include "hotseatgame/gameproperties.h"

#include "player.h"
#include "playermanager.h"
#include "race.h"
#include "racemanager.h"

#include "soundengine.h"


#include <QString>
#include <QStringList>
#include <QMovie>
#include <QDebug>
#include <QMouseEvent>

#include <vector>

RecruitmentScene::RecruitmentScene(QWidget *parent)
    : Scene(parent)
    , ui(new Ui::RecruitmentScene)
{
    ui->setupUi(this);

    movie = new QMovie(":/assets/hotseat_recruit/image.gif");\
    movie->setScaledSize(QSize(600, 420));
    movie->supportedFormats();
    ui->image->setMovie(movie);
    movie->start();

    watcher = new ButtonEventListener(this);
    ui->complete_choice_button->installEventFilter(watcher);
    ui->back_button->installEventFilter(watcher);


    // Создаём обработчик событий нажатия иконок рас
    race_icon_watcher = new RaceIconEventListener(this, this);

    for (unsigned i = 0; i < GameProperties::RACES_MAXNUM; i++) {
        QLabel* race_icon = findChild<QLabel*>("available_race_" + QString::number(i));
        if (race_icon)
            race_icon->installEventFilter(race_icon_watcher);
    }
    ui->chosen_race_image_->installEventFilter(race_icon_watcher);

    // Создаём обработчик событий нажатия иконок юнитов
    unit_icon_watcher = new UnitIconEventListener(this, this);

    for (unsigned i = 0; i < GameProperties::AVAILABLE_UNIT_MAXNUM; i++) {
        QLabel* unit_icon = findChild<QLabel*>("available_unit_" + QString::number(i));
        if (unit_icon)
            unit_icon->installEventFilter(unit_icon_watcher);
    }

    for (unsigned i = 0; i < GameProperties::MAX_PARTY_SIZE; i++) {
        QLabel* unit_icon = findChild<QLabel*>("chosen_unit_" + QString::number(i));
        if (unit_icon)
            unit_icon->installEventFilter(unit_icon_watcher);
    }
}

RecruitmentScene::~RecruitmentScene()
{
}

void RecruitmentScene::parseArgs(QString args) {
    QStringList list = args.split("|");
    if (list.size() < 2) {
        // TODO: ERROR MESSAGE - incorrect arguments number
        GuiSceneManager::getInstance().changeScene("main_menu");
    }

    current_player_id_ = list[0].toInt();
    current_player_ = PlayerManager::getInstance().getPlayer(current_player_id_);
    available_money_ = std::max(0, list[1].toInt());

    if (!current_player_) {
        // TODO: ERROR MESSAGE - incorrect argument - player_id;
        GuiSceneManager::getInstance().changeScene("main_menu");
    }

    DialogForm* form = qobject_cast<DialogForm*>(GuiSceneManager::getInstance().getScene("dialog_form"));
    if (!form)
        return;
    form->setTitle("Найм юнитов для игрока: " + current_player_->getPlayerName());
    form->setShowCancel(false);
    form->setText("Игрок \"" + current_player_->getPlayerName() + "\", пришло время вам набрать свой отряд!");
    GuiSceneManager::getInstance().show("dialog_form");
    form->exec();
    GuiSceneManager::getInstance().hide("dialog_form");
}

void RecruitmentScene::init() {
    current_money_ = available_money_;
    initAvailableRaces();
    initAvailableUnits();
    showChosenUnits();

    ui->title_->setText(
        "<p align=\"center\">Набор юнитов - " + current_player_->getPlayerName() + "</p>"
    );

    QString race_name = current_player_->getRace()->getRaceId();
    ui->chosen_race_image_->setText(
        "<img src=\":/assets/units/" + race_name + "/icon.png\" width=\"100\" height=\"100\"/>"
    );

    updateMoney();
}

Player *RecruitmentScene::getActivePlayer()
{
    return current_player_;
}

bool RecruitmentScene::buyUnit(std::shared_ptr<Unit> unit)
{
    if (!unit || unit->getCost() > current_money_ || current_player_->getUnits().size() >= GameProperties::MAX_PARTY_SIZE)
        return false;
    current_player_->addUnit(unit);
    current_money_ -= unit->getCost();
    updateMoney();
    showChosenUnits();
    return true;
}

bool RecruitmentScene::removeUnit(std::shared_ptr<Unit> unit) {
    current_money_ += unit->getCost();
    updateMoney();
    current_player_->deleteUnit(unit);
    showChosenUnits();
    return true;
}

void RecruitmentScene::initAvailableRaces() {
    auto races = RaceManager::getInstance().getAvailableRacesList();
    races_list.clear();
    for (unsigned i = 0; i < std::min(size_t(GameProperties::RACES_MAXNUM), races.size()); i++) {
        QString race_name = races[i];
        races_list.push_back(RaceManager::getInstance().getRace(race_name));
        QLabel* race_icon = findChild<QLabel*>("available_race_" + QString::number(i));
        if (race_icon)
            race_icon->setText("<img src=\":/assets/units/" + race_name + "/icon.png\" width=\"66\" height=\"66\"/>");
    }
}

void RecruitmentScene::initAvailableUnits() {
    auto units_list = current_player_->getRace()->getAllUnitsList();
    available_units_list.clear();
    for (unsigned i = 0; i < std::min(size_t(GameProperties::AVAILABLE_UNIT_MAXNUM), units_list.size()); i++) {
        QString race_name = current_player_->getRace()->getRaceId();
        QString unit_name = units_list[i]->getUnitId();
        available_units_list.push_back(units_list[i]);

        QLabel* unit_icon = findChild<QLabel*>("available_unit_" + QString::number(i));
        qDebug() << "<img src=\":/assets/units/" + race_name + "/" + unit_name + "/icon.png\" width=\"58\" height=\"58\"/>";
        if (unit_icon)
            unit_icon->setText("<img src=\":/assets/units/" + race_name + "/" + unit_name + "/icon.png\" width=\"58\" height=\"58\"/>");
    }
}

void RecruitmentScene::showChosenUnits() {
    unsigned counter = 0;
    chosen_units_list.clear();

    for (auto unit : current_player_->getUnits()) {
        if (counter >= GameProperties::MAX_PARTY_SIZE)
            break;
        QString unit_name = unit->getUnitId();
        chosen_units_list.push_back(unit);
        QString race_name = current_player_->getRace()->getRaceId();
        QLabel* unit_icon = findChild<QLabel*>("chosen_unit_" + QString::number(counter));
        if (unit_icon) {
            unit_icon->setText("<img src=\":/assets/units/" + race_name + "/" + unit_name + "/icon.png\" width=\"58\" height=\"58\"/>");
            unit_icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_default.png);\nbackground-color: rgb(253, 234, 168);");
        }
        counter++;
    }


    for (unsigned i = counter; i < GameProperties::MAX_PARTY_SIZE; i++) {
        QLabel* unit_icon = findChild<QLabel*>("chosen_unit_" + QString::number(i));
        if (unit_icon) {
            unit_icon->setText("");
            unit_icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_default.png);\nbackground-color: rgb(253, 234, 168);");
        }
    }
}

void RecruitmentScene::changeRace(std::shared_ptr<Race> race) {
    current_player_->clearUnits();
    current_player_->setRace(race);
    init();
}

void RecruitmentScene::updateMoney() {
   ui->available_money_text_->setText("Монеты: " + QString::number(current_money_));
}

void RecruitmentScene::on_back_button_clicked() {
    GuiSceneManager::getInstance().changeScene("pvp_intro");
}

void RecruitmentScene::on_complete_choice_button_clicked()
{
    qDebug() << "Exiting recruit army scene with player_id =" << current_player_id_;
    if (current_player_id_ == 0) {
        qDebug() << "Changing to 1";
        GuiSceneManager::getInstance().changeScene("recruit_army", "1|" + QString::number(available_money_));
    } else {
        GuiSceneManager::getInstance().changeScene("prebattle");
    }
}

RaceIconEventListener::RaceIconEventListener(QObject *parent, RecruitmentScene* scene)
    : QObject(parent)
    , scene_(scene)  {
}

bool RaceIconEventListener::eventFilter(QObject *watched, QEvent *event) {
    QLabel* icon = qobject_cast<QLabel*>(watched);
    if (!icon) {
        return false;
    }

    if (event->type() == QEvent::Enter) {

        if (icon->objectName() != "chosen_race_image_") {
            icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_hover.png);\nbackground-color: rgb(253, 234, 168);");

            SoundEngine::getInstance().playAsync("qrc:/assets/common/buttons/button_hover.mp3");

            unsigned race_id_number = icon->objectName().mid(icon->objectName().lastIndexOf('_') + 1).toInt();

            IconHint *hint = new IconHint(scene_);
            hint->setHintText("ЛКМ - сменить расу<br>ПКМ - открыть окно информации");
            hint->setHintTitle("Раса \"" + scene_->races_list[race_id_number]->getRaceName() + "\"");
            hint->move(icon->mapToGlobal(QPoint(0,0)).x() + icon->width() / 2 - hint->width() / 2, icon->mapToGlobal(QPoint(0,0)).y() + icon->height() + 2);
        } else {
            QString race_name = scene_->getActivePlayer()->getRace()->getRaceName();
            IconHint *hint = new IconHint(scene_);
            hint->setHintTitle("Раса \"" + race_name + "\"");
            hint->setHintText("ПКМ - открыть окно информации");
            hint->move(icon->mapToGlobal(QPoint(0,0)).x() + icon->width() / 2 - hint->width() / 2, icon->mapToGlobal(QPoint(0,0)).y() + icon->height() + 2);
        }
        return false;
    }

    if (event->type() == QEvent::Leave) {
        if (icon->objectName() != "chosen_race_image_") {
            icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_default.png);\nbackground-color: rgb(253, 234, 168);");
            SoundEngine::getInstance().playAsync("qrc:/assets/common/buttons/button_hover.mp3");
            if (!scene_)
                return false;
        }

        QList<IconHint*> hints = scene_->findChildren<IconHint*>("hint");
        for (auto &hint : hints) {
            hint->hide();
            hint->deleteLater();
        }
        return false;
    }

    if (event->type() == QEvent::MouseButtonPress) {
        if (icon->objectName() != "chosen_race_image_")
            icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_active.png);\nbackground-color: rgb(253, 234, 168);");
        SoundEngine::getInstance().playAsync("qrc:/assets/common/buttons/button_click.mp3");
    }

    if (event->type() == QEvent::MouseButtonRelease) {
        if (icon->objectName() != "chosen_race_image_")
            icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_hover.png);\nbackground-color: rgb(253, 234, 168);");

        QMouseEvent *evt = dynamic_cast<QMouseEvent*>(event);

        if (evt->button() == Qt::LeftButton) {
            if (icon->objectName() == "chosen_race_image_")
                return false;

            GuiSceneManager::getInstance().show("dialog_form");

            DialogForm* form = qobject_cast<DialogForm*>(GuiSceneManager::getInstance().getScene("dialog_form"));

            if (!form)
                return false;
            form->setTitle("Смена расы");
            form->setShowCancel(true);
            form->setText("Вы уверены, что хотите сменить расу? В этом случае все нанятые и улучшенные юниты исчезнут, а число монет будет восстановлено");
            form->exec();

            if (form->isOk()) {
                unsigned race_id_number = icon->objectName().mid(icon->objectName().lastIndexOf('_') + 1).toInt();
                scene_->changeRace(scene_->races_list[race_id_number]);
            }

            GuiSceneManager::getInstance().hide("dialog_form");
        }

        if (evt->button() == Qt::RightButton) {
            DialogForm* form = qobject_cast<DialogForm*>(GuiSceneManager::getInstance().getScene("dialog_form"));
            if (!form)
                return false;
            form->setTitle("Окно информации о расе");
            form->setShowCancel(false);
            form->setText("Окно информации о расе пока недоступно, извините");

            GuiSceneManager::getInstance().show("dialog_form");
            form->exec();
            GuiSceneManager::getInstance().hide("dialog_form");
            return false;
        }
    }

    return false;
}


UnitIconEventListener::UnitIconEventListener(QObject *parent, RecruitmentScene *scene)
    : QObject(parent)
    , scene_(scene)  {
}

bool UnitIconEventListener::eventFilter(QObject *watched, QEvent *event) {
    QLabel* icon = qobject_cast<QLabel*>(watched);
    if (!icon) {
        qDebug() << __FILE__ << " " << __LINE__ << " cannot cast to icon!";
        return false;
    }

    unsigned unit_id_number = icon->objectName().mid(icon->objectName().lastIndexOf('_') + 1).toInt();
    QString icon_name = icon->objectName();

    if (icon_name.contains("available_unit") && unit_id_number >= scene_->available_units_list.size()) {
        return false;
    }

    if (icon_name.contains("chosen_unit") && unit_id_number >= scene_->chosen_units_list.size()) {
        return false;
    }

    std::shared_ptr<Unit> unit;

    if (icon_name.contains("available_unit"))
        unit = scene_->available_units_list[unit_id_number];
    else
        unit = scene_->chosen_units_list[unit_id_number];

    if (event->type() == QEvent::Enter) {
        icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_hover.png);\nbackground-color: rgb(253, 234, 168);");
        SoundEngine::getInstance().playAsync("qrc:/assets/common/buttons/button_hover.mp3");

        IconHint *hint = new IconHint(scene_);
        hint->resize(300, 300);
        hint->setHintTitle(unit->getUnitName());

        QString buttons_hint;
        if (icon_name.contains("available_unit"))
            buttons_hint = "<br>ЛКМ - нанять юнита<br>ПКМ - информация и улучшения";
        if (icon_name.contains("chosen_unit"))
            buttons_hint = "<br>ЛКМ - информация и улучшения<br>ПКМ - вернуть юнита";

        hint->setHintText("Стоимость: " + QString::number(unit->getCost()) + buttons_hint);
        hint->move(icon->mapToGlobal(QPoint(0,0)).x() + icon->width() / 2 - hint->width() / 2, icon->mapToGlobal(QPoint(0,0)).y() + icon->height() + 2);
    }

    if (event->type() == QEvent::Leave) {
        icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_default.png);\nbackground-color: rgb(253, 234, 168);");
        SoundEngine::getInstance().playAsync("qrc:/assets/common/buttons/button_hover.mp3");
        QList<IconHint*> hints = scene_->findChildren<IconHint*>("hint");
        for (auto &hint : hints) {
            hint->hide();
            hint->deleteLater();
        }
    }

    if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) {
        icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_active.png);\nbackground-color: rgb(253, 234, 168);");
        SoundEngine::getInstance().playAsync("qrc:/assets/common/buttons/button_click.mp3");
    }

    if (event->type() == QEvent::MouseButtonRelease) {
        icon->setStyleSheet("border-image: url(:/assets/hotseat_recruit/unit_icon_hover.png);\nbackground-color: rgb(253, 234, 168);");
        QMouseEvent *evt = dynamic_cast<QMouseEvent*>(event);
        if (evt->button() == Qt::LeftButton) {
            if (icon_name.contains("available_unit")) {
                if (scene_->buyUnit(unit))
                    return false;
                DialogForm* form = qobject_cast<DialogForm*>(GuiSceneManager::getInstance().getScene("dialog_form"));
                if (!form)
                    return false;
                form->setTitle("Набор юнита " + unit->getUnitName());
                form->setShowCancel(false);
                form->setText("Не могу нанять юнита. Проверьте, возможно он слишком дорогой или для него нет места в отряде?");
                GuiSceneManager::getInstance().show("dialog_form");
                form->exec();
                GuiSceneManager::getInstance().hide("dialog_form");
                return false;
            }
            if (icon_name.contains("chosen_unit")) {
                DialogForm* form = qobject_cast<DialogForm*>(GuiSceneManager::getInstance().getScene("dialog_form"));
                if (!form) {
                    return false;
                }
                form->setTitle("Окно информации о юните " + unit->getUnitName());
                form->setShowCancel(false);
                form->setText("К сожалению, окно информации о юните и его улучшениях временно недоступно<br>В данной версии вы можете выбирать только из юнитов первого звена");
                GuiSceneManager::getInstance().show("dialog_form");
                form->exec();
                GuiSceneManager::getInstance().hide("dialog_form");
                return false;
            }
        }
        if (evt->button() == Qt::RightButton) {
            if (icon_name.contains("available_unit")) {
                DialogForm* form = qobject_cast<DialogForm*>(GuiSceneManager::getInstance().getScene("dialog_form"));
                if (!form) {
                    return false;
                }
                form->setTitle("Окно информации о юните " + unit->getUnitName());
                form->setShowCancel(false);
                form->setText("К сожалению, окно информации о юните и его улучшениях временно недоступно :( <br> В данной версии вы можете выбирать только из юнитов первого звена");
                GuiSceneManager::getInstance().show("dialog_form");
                form->exec();
                GuiSceneManager::getInstance().hide("dialog_form");
                return false;
            }
            if (icon_name.contains("chosen_unit")) {
                scene_->removeUnit(unit);
                QList<IconHint*> hints = scene_->findChildren<IconHint*>("hint");
                for (auto &hint : hints) {
                    hint->hide();
                    hint->deleteLater();
                }
                if (scene_->childAt(QCursor::pos()) == icon) {
                    QEvent *event = new QEvent(QEvent::Enter);
                    QCoreApplication::postEvent(icon, event);
                }
            }
        }
    }

    return false;
}


