// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2019 Casper Meijn <casper@meijn.net>
// SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org>

#ifndef WSDISCOVERYCLIENT_H
#define WSDISCOVERYCLIENT_H

#include "wsdiscoveryclient_export.h"
#include <QHash>
#include <QObject>
#include <QUrl>

#include <KDSoapClient/KDQName>

#include "KDSoapClient/kdsoap_version.h"

#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) && (KDSOAP_VERSION <= KDSOAP_VERSION_CHECK(2, 1, 1))
WSDISCOVERYCLIENT_EXPORT QDebug operator<<(QDebug dbg, const KDQName &qn);
#endif

class KDSoapHeaders;
class KDSoapMessage;
class KDSoapUdpClient;
class QHostAddress;
class WSDiscoveryTargetService;

/*!
 * \brief WSDiscoveryClient is a low-level helper for sending and receiving WS-Discovery messages.
 *
 * start() will bind to the network and start receveing messages.
 * When a message is received, it will trigger the signals probeMatchReceived() and
 * resolveMatchReceived(). You can send messages using sendProbe() and sendResolve().
 *
 * \see WSDiscoveryProbeJob for a more high level interface
 */
class WSDISCOVERYCLIENT_EXPORT WSDiscoveryClient : public QObject
{
    Q_OBJECT
public:
    /*!
     * Create a WSDiscoveryClient
     * \param parent The QObject parent
     */
    explicit WSDiscoveryClient(QObject *parent = nullptr);
    ~WSDiscoveryClient();

Q_SIGNALS:
    /*!
     * Emitted when a WS-Discovery probe match message is received. When a single message is reveived
     * with multiple matches, then multiple signals are emitted.
     * \param probeMatchService The service as described in the match
     */
    void probeMatchReceived(const WSDiscoveryTargetService &probeMatchService);

    /*!
     * Emitted when a WS-Discovery resolve match message is received.
     * \param probeMatchService The service as described in the match
     */
    // TODO: Rename parameter
    void resolveMatchReceived(const WSDiscoveryTargetService &probeMatchService);

public Q_SLOTS:
    /*!
     * Bind to the WS-Discovery network ports. After binding messages will be
     * received. It binds on both IPv4 and IPv6.
     * @param port the port to bind or 0 to pick a random port
     */
    // TODO: Rename to bind()
    void start(quint16 port = 0);

    /*!
     * Send a WS-Discovery probe message. This will cause all devices in the network
     * that match to \p typeList and \p scopeList to send a probeMatch back.
     * \param  typeList List of types that a device should match
     * \param  scopeList List of scoped that a device should match
     */
    void sendProbe(const QList<KDQName> &typeList, const QList<QUrl> &scopeList);

    /*!
     * Send a WS-Discovery resolve message. This will cause a specific device
     * in the network to send a resolveMatch back.
     * \param endpointReference The identifier of the device of interest
     */
    void sendResolve(const QString &endpointReference);

private Q_SLOTS:
    // TODO: Make implementation private
    void receivedMessage(const KDSoapMessage &replyMessage, const KDSoapHeaders &replyHeaders, const QHostAddress &senderAddress, quint16 senderPort);

private:
    KDSoapUdpClient *m_soapUdpClient;
};

#endif // WSDISCOVERYCLIENT_H
