#include "devices/physical/SerialDevice.h"

#include <algorithm>
#include <memory>
#include <string>

#include <QDateTime>

#include "core/memory/MemoryPool.h"
#include "hardware/drivers/serial/SerialQtDriver.h"
#include "message_bus/ingress/IIngressPort.h"
#include "message_bus/pipeline/PipelineContext.h"
#include "utils/logs/logging.h"

using softbus::hardware::drivers::serial::SerialQtDriver;

namespace softbus::devices::physical
{

SerialDevice::SerialDevice(std::unique_ptr<SerialQtDriver>     driver,
                           const Config&                       config,
                           const softbus::devices::DeviceInfo& info)
    : m_driver(std::move(driver))
    , m_config(config)
    , m_info(info)
{
}

SerialDevice::~SerialDevice()
{
    stop();
}

bool SerialDevice::start()
{
    if (!m_driver) {
        LOG_ERROR() << "SerialDevice: start called with null driver";
        return false;
    }

    m_driver->SetReadCallback([this](const std::vector<std::uint8_t>& data) { this->onRead(data); });
    m_driver->SetErrorCallback([this](const std::string& error) { this->onError(error); });

    LOG_INFO() << "SerialDevice: opening endpoint" << m_config.endpoint;
    return m_driver->Open(m_config.endpoint.toStdString());
}

void SerialDevice::stop()
{
    if (!m_driver) {
        return;
    }

    LOG_INFO() << "SerialDevice: closing endpoint" << m_config.endpoint;
    m_driver->Close();
}

softbus::devices::DeviceInfo SerialDevice::deviceInfo() const
{
    return m_info;
}

QString SerialDevice::endpoint() const
{
    return m_config.endpoint;
}

softbus::devices::DeviceKind SerialDevice::kind() const
{
    return softbus::devices::DeviceKind::Serial;
}

void SerialDevice::bindIngress(softbus::message_bus::ingress::IIngressPort* ingress,
                               std::shared_ptr<softbus::core::memory::MemoryPool> pool)
{
    m_ingress = ingress;
    m_pool = std::move(pool);
}

// 串口写入数据回调 不定长数据
bool SerialDevice::writePayload(const std::vector<std::uint8_t>& data)
{
    if (!m_driver) {
        return false;
    }
    return m_driver->Write(data);
}
// 串口写入数据回调 定长数据
bool SerialDevice::writePayload(const std::uint8_t* data, std::size_t size)
{
    if (!m_driver) {
        return false;
    }
    return m_driver->Write(data, size);
}

// 串口读取数据回调

void SerialDevice::onRead(const std::vector<std::uint8_t>& data)
{
    if (!m_ingress || !m_pool || data.empty()) {
        return;
    }

    auto block = m_pool->allocate(data.size());
    if (!block || !block->data || block->capacity < data.size()) {
        m_ingress->reportError(m_config.endpoint, QStringLiteral("memory pool exhausted"));
        return;
    }

    std::copy(data.begin(), data.end(), block->data);
    block->size = data.size();
    // @test code
    LOG_INFO() << "SerialDevice: onRead data size" << data.size() << "endpoint" << m_config.endpoint;
    // 将数据推送到 ingress 队列 包含端口名、协议、数据、时间戳、traceId
    softbus::message_bus::pipeline::PipelineContext ctx;
    ctx.endpoint = m_config.endpoint;
    ctx.protocolHint = m_info.protocol;
    ctx.payload.block = std::move(block);
    ctx.payload.length = data.size();
    ctx.payloadSize = data.size();
    ctx.traceId = QStringLiteral("serial:%1:%2")
                      .arg(m_config.endpoint)
                      .arg(QDateTime::currentMSecsSinceEpoch());

    if (!m_ingress->push(std::move(ctx))) {
        m_ingress->reportError(m_config.endpoint, QStringLiteral("ingress queue full"));
    }
}

void SerialDevice::onError(const std::string& error)
{
    if (!m_ingress) {
        return;
    }
    m_ingress->reportError(m_config.endpoint, QString::fromStdString(error));
}

} // namespace softbus::devices::physical

