#include "api/http/RestApiServer.h"

#include <QHostAddress>
#include <QHttpServer>
#include <QTcpServer>

#include "api/http/RestApiHttpConfig.h"
#include "api/http/RestApiRoutes.h"
#include "api/ipc_dbus/CommandDispatcher.h"
#include "utils/logs/logging.h"

namespace softbus::api::http
{

struct RestApiServer::Impl
{
    std::unique_ptr<softbus::api::ipc::CommandDispatcher> dispatcher;
    std::unique_ptr<QHttpServer> http;
    std::unique_ptr<QTcpServer> tcp;
};

RestApiServer::RestApiServer(QObject* parent)
    : QObject(parent)
    , m_impl(std::make_unique<Impl>())
{
    m_impl->dispatcher = std::make_unique<softbus::api::ipc::CommandDispatcher>();
}

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

void RestApiServer::stop()
{
    if (!m_impl || !m_impl->http) {
        return;
    }
    m_impl->http->disconnect();
    m_impl->http.reset();
    m_impl->tcp.reset();
}

bool RestApiServer::tryStartFromConfigFile(const QString& configPath, QString* err)
{
    if (!m_impl || !m_impl->dispatcher) {
        if (err) {
            *err = QStringLiteral("internal_error");
        }
        return false;
    }

    RestApiHttpListenOptions opts;
    if (!loadRestApiHttpListenOptions(configPath, &opts, err)) {
        return false;
    }
    if (!opts.sectionPresent) {
        LOG_INFO() << "RestApiServer: no api.http section, HTTP disabled";
        return true;
    }
    if (!opts.enabled) {
        LOG_INFO() << "RestApiServer: api.http.enabled is false or missing, HTTP disabled";
        return true;
    }

    if (opts.port <= 0 || opts.port > 65535) {
        if (err) {
            *err = QStringLiteral("invalid_port");
        }
        return false;
    }

    stop();

    m_impl->http = std::make_unique<QHttpServer>(this);
    m_impl->tcp = std::make_unique<QTcpServer>();

    QHttpServer* srv = m_impl->http.get();
    registerSoftbusRestApiRoutes(srv, this, m_impl->dispatcher.get());

    const QHostAddress addr(opts.bindHost);
    if (addr.isNull()) {
        if (err) {
            *err = QStringLiteral("invalid_bind_address");
        }
        stop();
        return false;
    }

    if (!m_impl->tcp->listen(addr, static_cast<quint16>(opts.port))) {
        if (err) {
            *err = QStringLiteral("tcp_listen_failed");
        }
        LOG_ERROR() << "RestApiServer: listen failed bind=" << opts.bindHost << "port=" << opts.port
                    << "err=" << m_impl->tcp->errorString();
        stop();
        return false;
    }

    if (!srv->bind(m_impl->tcp.get())) {
        if (err) {
            *err = QStringLiteral("http_bind_failed");
        }
        LOG_ERROR() << "RestApiServer: QHttpServer::bind failed";
        stop();
        return false;
    }

    (void)m_impl->tcp.release();

    LOG_INFO() << "RestApiServer: listening http://" << opts.bindHost << ":" << opts.port;
    return true;
}

} // namespace softbus::api::http
