// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtCore/QDateTime>
#include <QtMqtt/QMqttClient>
#include <QtWidgets/QMessageBox>

using namespace Qt::StringLiterals;

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

    m_client = new QMqttClient(this);
    m_client->setHostname(ui->lineEditHost->text());
    m_client->setPort(static_cast<quint16>(ui->spinBoxPort->value()));

    connect(m_client, &QMqttClient::stateChanged, this, &MainWindow::updateLogStateChange);
    connect(m_client, &QMqttClient::disconnected, this, &MainWindow::brokerDisconnected);

    connect(m_client, &QMqttClient::messageReceived, this, [this](const QByteArray &message, const QMqttTopicName &topic) {
        const QString content = QDateTime::currentDateTime().toString()
                    + " Received Topic: "_L1
                    + topic.name()
                    + " Message: "_L1
                    + message
                    + u'\n';
        ui->editLog->insertPlainText(content);
    });

    connect(m_client, &QMqttClient::pingResponseReceived, this, [this]() {
        const QString content = QDateTime::currentDateTime().toString()
                    + "PingResponse\n"_L1;
        ui->editLog->insertPlainText(content);
    });

    connect(ui->lineEditHost, &QLineEdit::textChanged, m_client, &QMqttClient::setHostname);
    connect(ui->spinBoxPort, QOverload<int>::of(&QSpinBox::valueChanged), this, &MainWindow::setClientPort);
    connect(ui->checkBoxWebSockets, &QCheckBox::checkStateChanged, this, [this](int ws) { setWebSockets(ws != 0); });
    connect(ui->checkBoxSecure, &QCheckBox::checkStateChanged, this, [this](int s) { setSecure(s != 0); } );
    connect(ui->comboBoxProtocol, &QComboBox::currentIndexChanged, this, [this](int p) { setProtocol(static_cast<QMqttClient::ProtocolVersion>(p + 3)); });
    updateLogStateChange();
}

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

void MainWindow::on_buttonConnect_clicked()
{
    if (m_client->state() == QMqttClient::Disconnected) {
        ui->lineEditHost->setEnabled(false);
        ui->spinBoxPort->setEnabled(false);
        ui->buttonConnect->setText(tr("Disconnect"));

        m_client->setProtocolVersion(m_protocol);

        if (m_secure && m_webSockets)
            m_client->connectToHostWebSocketEncrypted();
#if !defined(QT_NO_SSL) && !defined(Q_OS_WASM)
        if (m_secure && !m_webSockets)
            m_client->connectToHostEncrypted({});
#endif
        if (!m_secure && m_webSockets)
            m_client->connectToHostWebSocket();
#if !defined(Q_OS_WASM)
        if (!m_secure && !m_webSockets)
            m_client->connectToHost();
#endif
        if (m_client->state() == QMqttClient::Disconnected) {
            ui->lineEditHost->setEnabled(true);
            ui->spinBoxPort->setEnabled(true);
            ui->buttonConnect->setText(tr("Connect"));
            m_client->disconnectFromHost();
        }
    } else {
        ui->lineEditHost->setEnabled(true);
        ui->spinBoxPort->setEnabled(true);
        ui->buttonConnect->setText(tr("Connect"));
        m_client->disconnectFromHost();
    }
}

void MainWindow::on_buttonQuit_clicked()
{
    QApplication::quit();
}

void MainWindow::updateLogStateChange()
{
    const QString content = QDateTime::currentDateTime().toString()
                    + ": State Change"_L1
                    + QString::number(m_client->state())
                    + u'\n';
    ui->editLog->insertPlainText(content);
}

void MainWindow::brokerDisconnected()
{
    ui->lineEditHost->setEnabled(true);
    ui->spinBoxPort->setEnabled(true);
    ui->buttonConnect->setText(tr("Connect"));
}

void MainWindow::setClientPort(int p)
{
    m_client->setPort(static_cast<quint16>(p));
}

void MainWindow::setSecure(bool s)
{
    m_secure = s;
}

void MainWindow::setWebSockets(bool ws)
{
    m_webSockets = ws;
}

void MainWindow::setProtocol(QMqttClient::ProtocolVersion p)
{
    m_protocol = p;
}

void MainWindow::on_buttonPublish_clicked()
{
    if (m_client->publish(ui->lineEditTopic->text(), ui->lineEditMessage->text().toUtf8()) == -1)
        QMessageBox::critical(this, u"Error"_s, u"Could not publish message"_s);
}

void MainWindow::on_buttonSubscribe_clicked()
{
    auto subscription = m_client->subscribe(ui->lineEditTopic->text());
    if (!subscription) {
        QMessageBox::critical(this, u"Error"_s,
                              u"Could not subscribe. Is there a valid connection?"_s);
        return;
    }
}
