#include "cascade_client.h"

#include <utility>
#include <QtEndian>
#include "common/spdlog/logging.h"

namespace zsy
{
    CascadeClient::CascadeClient(QString host, const quint16 port, QObject *parent)
        : QObject(parent)
          , status(UNAVAILABLE)
          , host(std::move(host))
          , port(port)
          , socket(new QTcpSocket(this))
    {
        connect(socket, &QTcpSocket::connected, this, &CascadeClient::onConnected);
        connect(socket, &QTcpSocket::readyRead, this, &CascadeClient::onReadyRead);
        connect(socket, &QTcpSocket::disconnected, this, &CascadeClient::onDisconnected);
        connect(socket, &QTcpSocket::errorOccurred, this, &CascadeClient::onError);
        status.store(STOPPED);
        start();
    }

    CascadeClient::~CascadeClient()
    {
        if (socket->state() == QTcpSocket::ConnectedState)
        {
            status.store(UNAVAILABLE);
            socket->close();
        }
    }

    void CascadeClient::start()
    {
        uint8_t expected = STOPPED;
        if (status.compare_exchange_strong(expected, STARTED))
        {
            if (socket == nullptr)
            {
                socket = new QTcpSocket(this);
            }
            socket->connectToHost(host, port);
        }
    }

    void CascadeClient::stop()
    {
        uint8_t expected = STARTED;
        if (status.compare_exchange_strong(expected, STOPPED))
        {
            socket->close();
            delete socket;
            socket = nullptr;
        }
    }

    void CascadeClient::restart()
    {
        LOGGER_INFO("正在重新连接：{}:{}", host.toStdString(), port);
        stop();
        start();
    }

    void CascadeClient::restart(const QString &host, quint16 port)
    {
        this->host = host;
        this->port = port;
        restart();
    }

    void CascadeClient::sendData(const QByteArray &data)
    {
        if (status.load() != STARTED || socket == nullptr || socket->state() != QTcpSocket::ConnectedState)
        {
            LOGGER_WARN("未连接服务器，不能发送数据，{}:{}", host.toStdString(), port);
            return;
        }
        try
        {
            socket->write(data);
            socket->flush();
        } catch (std::exception &e)
        {
            LOGGER_ERROR("数据发送失败：{}", e.what());
        } catch (...)
        {
            LOGGER_ERROR("未知错误，数据发送失败");
        }
    }

    void CascadeClient::onConnected()
    {
        LOGGER_INFO("服务器连接成功：{}:{}", host.toStdString(), port);
    }

    void CascadeClient::onDisconnected()
    {
        LOGGER_WARN("已断开连接：{}:{}", host.toStdString(), port);
        restart();
    }

    void CascadeClient::onError(const QAbstractSocket::SocketError error)
    {
        LOGGER_ERROR("出现错误，原因：{}，{}", static_cast<int8_t>(error), socket->errorString().toStdString());
        restart();
    }

    void CascadeClient::onReadyRead()
    {
        const QByteArray data = socket->readAll();
        buffer.append(data);
        while (true)
        {
            std::shared_ptr<CascadeMessage> message = nullptr;
            const qint64 bufferSize = buffer.size();
            if (bufferSize < 20) break;
            if (const quint32 head = qFromBigEndian(*reinterpret_cast<const quint32 *>(buffer.mid(0, 4).data()));
                head != CascadeMessage::HEAD)
            {
                buffer.remove(0, 4);
                break;
            }
            const quint32 len = qFromBigEndian(*reinterpret_cast<const quint32 *>(buffer.mid(16, 4).data()));
            if (bufferSize < 21 + len)
            {
                break;
            }
            if (const quint8 tail = qFromBigEndian(*reinterpret_cast<const quint8 *>(buffer.mid(20 + len, 1).data()));
                tail != CascadeMessage::TAIL)
            {
                buffer.remove(0, 21 + len);
                break;
            }

            const qint32 fnc = qFromBigEndian(*reinterpret_cast<const qint32 *>(buffer.mid(4, 4).data()));
            const qint64 flc = qFromBigEndian(*reinterpret_cast<const qint64 *>(buffer.mid(8, 8).data()));

            if (len > 0)
            {
                message = std::make_shared<CascadeMessage>(fnc, flc, std::move(buffer.mid(20, len)));
            } else
            {
                message = std::make_shared<CascadeMessage>(fnc, flc);
            }
            buffer.remove(0, 21 + len);
            if (message == nullptr) break;
            // 触发事件
        }
    }
} // zsy