/*
 * This file is part of Skyward Hub.
 *
 * Skyward Hub is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * Skyward Hub is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * Skyward Hub. If not, see <https://www.gnu.org/licenses/>.
 *
 */

#include "RefuelingVisualizer.h"

#include <Components/FilterSelector/FilterSelector.h>
#include <Core/MessageBroker/MessageBroker.h>

#include <QDebug>
#include <QElapsedTimer>

RefuelingVisualizer::RefuelingVisualizer(QWidget* parent)
    : DefaultModule(parent)
{
    valveLabelStyleOFF =
        "border-width: 1px; border-style: solid; border-radius: 1px; "
        "border-color: white;";
    valveLabelStyleON =
        "border-width: 1px; border-style: solid; border-radius: 1px; "
        "border-color: white;";
    HeaderStyle =
        "border-width: 1px; border-style: solid; border-color: "
        "rgb(100, 100, "
        "100); background-color: rgba(51, 153, 255, 7%);"
        "border-bottom-style: double; font: bold; "
        "border-bottom-left-radius: "
        "0px; border-bottom-right-radius: 0px;";
    std_headStyle =
        "border-width: 1px; border-style: dashed; border-color: "
        "rgb(100, 100, "
        "100); border-radius: 0px; border-left-style: solid; "
        "border-right-style: solid;";
    lst_headStyle =
        "border-width: 1px; border-style: solid; border-color: "
        "rgb(100, 100, "
        "100); border-radius: 0px; border-top-style: dashed; "
        "border-bottom-left-radius: 1px; border-bottom-right-radius: "
        "1px;";
    dataStyle = "border-width: 0px;";

    setupUi();
    // customContextMenuActionSetup();

    getCore()->getMessageBroker()->subscribe(
        Filter::fromString("Mav/GSE_TM"), this,
        [this](const Message& message, const Filter& filter)
        {
            QElapsedTimer timer;
            timer.start();
            onMsgReceivedGSE(message);
            long long int time = timer.elapsed();
            qDebug() << "GSE" << time;
        });

    getCore()->getMessageBroker()->subscribe(
        Filter::fromString("Mav/MOTOR_TM"), this,
        [this](const Message& message, const Filter& filter)
        {
            QElapsedTimer timer;
            timer.start();
            onMsgReceivedMOT(message);
            long long int time = timer.elapsed();
            qDebug() << "MOTOR" << time;
        });
}

RefuelingVisualizer::~RefuelingVisualizer()
{
    getCore()->getMessageBroker()->unsubscribe(Filter::fromString("Mav/GSE_TM"),
                                               this);
    getCore()->getMessageBroker()->unsubscribe(
        Filter::fromString("Mav/MOTOR_TM"), this);
}

QWidget* RefuelingVisualizer::toWidget() { return this; }

XmlObject RefuelingVisualizer::toXmlObject()
{
    XmlObject obj(getName(ModuleId::REFUELING_VISUALIZER));

    return obj;
}

void RefuelingVisualizer::fromXmlObject(const XmlObject& xmlObject)
{
    if (xmlObject.getObjectName() == getName(ModuleId::REFUELING_VISUALIZER))
    {
        // nothing to do
    }
}

void RefuelingVisualizer::addQLabels()
{
    for (int i = 0; i < QLabelsList.count(); i++)
    {
        QString type = QLabelsList[i].info.type;

        // Valve's tabs
        if (type == "valve")
        {
            QLabel* Label = new QLabel;
            Label->setStyleSheet(
                "border-width: 1px; border-style: solid; border-radius: 1px; "
                "border-color: white; background-color: transparent; color: "
                "black");
            Label->setAlignment(Qt::AlignCenter);
            Label->setText(QLabelsList[i].info.name);
            QLabelsList[i].Label = Label;
            outerLayout->addWidget(
                Label, QLabelsList[i].info.y0, QLabelsList[i].info.x0,
                QLabelsList[i].info.dy, QLabelsList[i].info.dx);
        }
        // Headers
        else if (type == "header")
        {
            QLabel* Label = new QLabel;
            Label->setStyleSheet(HeaderStyle);
            Label->setAlignment(Qt::AlignCenter);
            Label->setText(QLabelsList[i].info.name);
            QLabelsList[i].Label = Label;
            outerLayout->addWidget(
                Label, QLabelsList[i].info.y0, QLabelsList[i].info.x0,
                QLabelsList[i].info.dy, QLabelsList[i].info.dx);
        }
        // Standard heads
        else if (type == "std_head")
        {
            QLabel* Label = new QLabel;
            Label->setStyleSheet(std_headStyle);
            Label->setAlignment(Qt::AlignLeft);
            Label->setText(QLabelsList[i].info.name);
            QLabelsList[i].Label = Label;
            outerLayout->addWidget(
                Label, QLabelsList[i].info.y0, QLabelsList[i].info.x0,
                QLabelsList[i].info.dy, QLabelsList[i].info.dx);
        }
        // Last heads
        else if (type == "lst_head")
        {
            QLabel* Label = new QLabel;
            Label->setStyleSheet(lst_headStyle);
            Label->setAlignment(Qt::AlignLeft);
            Label->setText(QLabelsList[i].info.name);
            QLabelsList[i].Label = Label;
            outerLayout->addWidget(
                Label, QLabelsList[i].info.y0, QLabelsList[i].info.x0,
                QLabelsList[i].info.dy, QLabelsList[i].info.dx);
        }
        // Data
        else
        {
            QLineEdit* Label = new QLineEdit;
            Label->setStyleSheet(dataStyle);
            Label->setAlignment(Qt::AlignRight);
            Label->setText(QLabelsList[i].info.name);
            QLabelsList[i].Text = Label;
            outerLayout->addWidget(
                Label, QLabelsList[i].info.y0, QLabelsList[i].info.x0,
                QLabelsList[i].info.dy, QLabelsList[i].info.dx);
        }
    }
    setLayout(outerLayout);
}

void RefuelingVisualizer::setupUi()
{
    // SET OUTER LAYOUT
    outerLayout = new QGridLayout;
    outerLayout->setContentsMargins(0, 0, 0, 0);
    outerLayout->setSpacing(0);

    // DEFAULT BACKGROUND IMAGE
    background = new QLabel;
    background->setStyleSheet("background-color: transparent;");
    background->setGeometry(0, 0, 700, 910);
    outerLayout->addWidget(background, 0, 0, 5000, 5000);
    backgroundPreSet();

    background->setAutoFillBackground(true);
    background->setPalette(backgroundList[0]);
    background->update();

    // CREATE QLABELS
    addQLabels();
}

void RefuelingVisualizer::backgroundPreSet()
{
    QPalette newPal;
    for (int i = 0; i < 8; i++)
    {
        pixmapList.append(
            QPixmap("../skywardhub/src/shared/Modules/RefuelingVisualizer/" +
                    backgroundNames[i] + ".png"));
        pixmapList[i] =
            pixmapList[i].scaled(background->size(), Qt::IgnoreAspectRatio);

        /* pixmapList[i] = pixmapList[i].scaledToHeight(background->height(),
                                                     Qt::FastTransformation); */
        backgroundList.append(newPal);
        backgroundList[i].setBrush(QPalette::Window, pixmapList[i]);
    }
}

void RefuelingVisualizer::changeValves(int i, uint64_t status)
{
    auto widget           = QLabelsList[i].Label;
    QLabelsList[i].status = status;

    // change valve's tab
    widget->setAutoFillBackground(true);
    QPalette pal = widget->palette();
    if (status == 0)
    {
        pal.setColor(QPalette::Window, Qt::red);
        pal.setColor(QPalette::WindowText, Qt::black);
        pal.setColor(QPalette::Text, Qt::black);
    }
    else
    {
        pal.setColor(QPalette::Window, Qt::green);
        pal.setColor(QPalette::WindowText, Qt::black);
        pal.setColor(QPalette::Text, Qt::black);
    }
    widget->setPalette(pal);
    widget->update();

    // Background
    background->setAutoFillBackground(true);
    int index = backgroundNames.indexOf(QString::number(QLabelsList[0].status) +
                                        QString::number(QLabelsList[1].status) +
                                        QString::number(QLabelsList[2].status));
    background->setPalette(backgroundList[index]);
    background->update();
}

void RefuelingVisualizer::changeData(int i, const Message& msg)
{
    auto widget = QLabelsList[i].Text;
    float value = msg.getField(QLabelsList[i].msg.message).getDouble();
    widget->setText(QString::number(value, 'f', 3) + QLabelsList[i].info.name);
}

void RefuelingVisualizer::onMsgReceivedGSE(const Message& msg)
{
    // Loop over the whole QLabels list
    for (int i = 0; i < QLabelsList.count(); i++)
    {
        // Check if the needed message comes from GSE_TM
        if (QLabelsList[i].msg.topic == "GSE")
        {
            // DISTINGUISH BETWEEN VALVES AND DATA
            // Valves
            if (QLabelsList[i].info.type == "valve")
            {
                uint64_t test = msg.getField(QLabelsList[i].msg.message)
                                    .getUnsignedInteger();
                if (test != QLabelsList[i].status)
                {
                    changeValves(i, test);
                }
            }
            // Data
            else
            {
                changeData(i, msg);
            }
        }
    }
}

void RefuelingVisualizer::onMsgReceivedMOT(const Message& msg)
{
    // Loop over the whole QLabels list
    for (int i = 0; i < QLabelsList.count(); i++)
    {
        // Check if the needed message comes from GSE_TM
        if (QLabelsList[i].msg.topic == "MOT")
        {
            // DISTINGUISH BETWEEN VALVES AND DATA
            // Valves
            if (QLabelsList[i].info.type == "valve")
            {
                uint64_t test = msg.getField(QLabelsList[i].msg.message)
                                    .getUnsignedInteger();
                if (test != QLabelsList[i].status)
                {
                    changeValves(i, test);
                }
            }
            // Data
            else
            {
                changeData(i, msg);
            }
        }
    }
}