/*
 * nRF5340 DK + W5500 (SPI) + Zephyr (NCS 3.1.1)
 * Ethernet via W5500 (DHCPv4) + MQTT v5.0 over TCP (no TLS)
 */

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/dhcpv4.h>
#include <zephyr/net/net_ip.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/mqtt.h>
#include <zephyr/sys/util.h>   /* MIN() */
#include <stdbool.h>
#include <string.h>

#include <zephyr/random/random.h>
#include <zephyr/posix/poll.h>
#include <errno.h>

// Local Project Settings
#include "config.h"
#include "certs.h"
#define APP_BMEM
#define APP_DMEM

LOG_MODULE_REGISTER(app, LOG_LEVEL_INF);

/* Buffers for MQTT client. */
static APP_BMEM uint8_t rx_buffer[APP_MQTT_BUFFER_SIZE];
static APP_BMEM uint8_t tx_buffer[APP_MQTT_BUFFER_SIZE];

/* The mqtt client struct */
static APP_BMEM struct mqtt_client client;

/* MQTT Broker details. */
static APP_BMEM struct sockaddr_storage broker;

static APP_BMEM struct pollfd fds[1];
static APP_BMEM int nfds;
static APP_BMEM bool connected;

/* Whether to include full topic in the publish message, or alias only (MQTT 5). */
static APP_BMEM bool include_topic;
static APP_BMEM bool aliases_enabled;

#define APP_TOPIC_ALIAS 1

#define TLS_SNI_HOSTNAME BROKER_NAME
#define APP_CA_CERT_TAG 1
#define APP_PSK_TAG 2

static APP_DMEM sec_tag_t m_sec_tags[] = {APP_CA_CERT_TAG};

// Initialize TLS credentials
static int tls_init(void)
{
    int err;
    
    LOG_INF("Adding CA certificate (size: %d bytes)", sizeof(ca_certificate_pem));
    LOG_HEXDUMP_DBG(ca_certificate_pem, sizeof(ca_certificate_pem), "Certificate:");
    
    /* First delete any existing credential */
    tls_credential_delete(APP_CA_CERT_TAG, TLS_CREDENTIAL_CA_CERTIFICATE);
    
    /* Add the CA certificate */
    err = tls_credential_add(APP_CA_CERT_TAG,
                           TLS_CREDENTIAL_CA_CERTIFICATE,
                           ca_certificate_pem,
                           sizeof(ca_certificate_pem) - 1);  // Subtract 1 to exclude null terminator
    
    if (err < 0) {
        LOG_ERR("Failed to register CA certificate: %d (0x%x)", err, -err);
        return err;
    }

    LOG_INF("Successfully added CA certificate");
    return 0;
}

// Prepare file descriptors for poll()
static void prepare_fds(struct mqtt_client *client)
{
	if (client->transport.type == MQTT_TRANSPORT_NON_SECURE) {
		fds[0].fd = client->transport.tcp.sock;
	}
	else if (client->transport.type == MQTT_TRANSPORT_SECURE) {
		fds[0].fd = client->transport.tls.sock;
	}

	fds[0].events = POLLIN;
	nfds = 1;
}

// Clear file descriptors
static void clear_fds(void)
{
	nfds = 0;
}

// Wait for socket events with timeout
static int wait(int timeout)
{
	int ret = 0;

	if (nfds > 0) {
		ret = poll(fds, nfds, timeout);
		if (ret < 0) {
			LOG_ERR("poll error: %d", errno);
		}
	}

	return ret;
}

// MQTT event handler
void mqtt_evt_handler(struct mqtt_client *const client,
		      const struct mqtt_evt *evt)
{
	int err;

	switch (evt->type) {
	case MQTT_EVT_CONNACK:
        // Check if connection was successful
		if (evt->result != 0) {
			LOG_ERR("MQTT connect failed %d", evt->result);
			break;
		}
		connected = true;
		LOG_INF("MQTT client connected!");

        // Check if broker supports topic aliases
		if (evt->param.connack.prop.rx.has_topic_alias_maximum &&
		    evt->param.connack.prop.topic_alias_maximum > 0) {
			LOG_INF("Topic aliases allowed by the broker, max %u.",
				evt->param.connack.prop.topic_alias_maximum);

			aliases_enabled = true;
		} else {
			LOG_INF("Topic aliases disallowed by the broker.");
		}

		break;

	case MQTT_EVT_DISCONNECT:
		// Handle disconnection
        LOG_INF("MQTT client disconnected %d", evt->result);

		connected = false;
		clear_fds();

		break;

	case MQTT_EVT_PUBACK:
		// Handle PUBACK for QoS
        if (evt->result != 0) {
			LOG_ERR("MQTT PUBACK error %d", evt->result);
			break;
		}

		LOG_INF("PUBACK packet id: %u", evt->param.puback.message_id);

		break;

	case MQTT_EVT_PUBREC:
        // Handle PUBREC for QoS
		if (evt->result != 0) {
			LOG_ERR("MQTT PUBREC error %d", evt->result);
			break;
		}

		LOG_INF("PUBREC packet id: %u", evt->param.pubrec.message_id);

		const struct mqtt_pubrel_param rel_param = {
			.message_id = evt->param.pubrec.message_id
		};

		err = mqtt_publish_qos2_release(client, &rel_param);
		if (err != 0) {
			LOG_ERR("Failed to send MQTT PUBREL: %d", err);
		}

		break;

	case MQTT_EVT_PUBCOMP:
        // Handle PUBCOMP for QoS
		if (evt->result != 0) {
			LOG_ERR("MQTT PUBCOMP error %d", evt->result);
			break;
		}

		LOG_INF("PUBCOMP packet id: %u",
			evt->param.pubcomp.message_id);

		break;

	case MQTT_EVT_PINGRESP:
        // Handle PINGRESP
		LOG_INF("PINGRESP packet");
		break;

	default:
		break;
	}
}

// Generate MQTT payload based on QoS
static char *get_mqtt_payload(enum mqtt_qos qos)
{
    static APP_DMEM char payload[] = "DOORS:OPEN_QoSx";

	payload[strlen(payload) - 1] = '0' + qos;

	return payload;
}

// Generate MQTT topic based on configuration
static char *get_mqtt_topic(void)
{
#if APP_HOSPITAL_TOPIC
	return "iot-2/type/"HOSPITAL_DEVTYPE"/id/"HOSPITAL_DEVID
	       "/evt/"HOSPITAL_EVENT"/fmt/"HOSPITAL_FORMAT;
#else
	return "Testing/Zephyr/MQTT";
#endif
}

// Publish MQTT message with given QoS
static int publish(struct mqtt_client *client, enum mqtt_qos qos)
{
	struct mqtt_publish_param param = { 0 };

	/* Always true for MQTT 3.1.1.
	 * True only on first publish message for MQTT 5.0 if broker allows aliases.
	 */
	if (include_topic) {
		param.message.topic.topic.utf8 = (uint8_t *)get_mqtt_topic();
		param.message.topic.topic.size =
			strlen(param.message.topic.topic.utf8);
	}

	param.message.topic.qos = qos;
	param.message.payload.data = get_mqtt_payload(qos);
	param.message.payload.len =
			strlen(param.message.payload.data);
	param.message_id = sys_rand16_get();
	param.dup_flag = 0U;
	param.retain_flag = 0U;

	if (aliases_enabled) {
		param.prop.topic_alias = APP_TOPIC_ALIAS;
		include_topic = false;
	}

	return mqtt_publish(client, &param);
}


#define RC_STR(rc) ((rc) == 0 ? "OK" : "ERROR")

// Macro to print function results
#define PRINT_RESULT(func, rc) \
	LOG_INF("%s: %d <%s>", (func), rc, RC_STR(rc))

// Initialize broker address
static void broker_init(void)
{
    struct sockaddr_in *broker4 = (struct sockaddr_in *)&broker;

	broker4->sin_family = AF_INET;
	broker4->sin_port = htons(BROKER_PORT);
	int aerr = net_addr_pton(AF_INET, BROKER_IP, &broker4->sin_addr);
    if (aerr) {
        LOG_INF("net_addr_pton failed (%d) for %s", aerr, BROKER_IP);
    }

}

// Initialize MQTT client
static void client_init(struct mqtt_client *client)
{
    mqtt_client_init(client);

    broker_init();

    /* MQTT client configuration */
    client->broker = &broker;
    client->evt_cb = mqtt_evt_handler;
    client->client_id.utf8 = (uint8_t *)CLIENT_ID;
    client->client_id.size = strlen(CLIENT_ID);
    client->password = NULL;
    client->user_name = NULL;
    client->protocol_version = MQTT_VERSION_5_0;

    /* MQTT buffers configuration */
    client->rx_buf = rx_buffer;
    client->rx_buf_size = sizeof(rx_buffer);
    client->tx_buf = tx_buffer;
    client->tx_buf_size = sizeof(tx_buffer);

    /* MQTT transport configuration */
    client->transport.type = MQTT_TRANSPORT_SECURE;

    struct mqtt_sec_config *tls_config = &client->transport.tls.config;
    tls_config->peer_verify = TLS_PEER_VERIFY_REQUIRED;
    tls_config->cipher_count = 0;                         // Let mbedTLS choose ciphers
    tls_config->cipher_list = NULL;
    tls_config->sec_tag_list = m_sec_tags;
    tls_config->sec_tag_count = ARRAY_SIZE(m_sec_tags);
    tls_config->hostname = TLS_SNI_HOSTNAME;              // Must match cert CN
    tls_config->cert_nocopy = 0;                         // Copy certificates

    LOG_INF("TLS configuration complete");
}

// Process MQTT events and maintain connection
static int process_mqtt_and_sleep(struct mqtt_client *client, int timeout)
{
	int64_t remaining = timeout;
	int64_t start_time = k_uptime_get();
	int rc;

	while (remaining > 0 && connected) {
		if (wait(remaining)) {
			rc = mqtt_input(client);
			if (rc != 0) {
				PRINT_RESULT("mqtt_input", rc);
				return rc;
			}
		}

		rc = mqtt_live(client);
		if (rc != 0 && rc != -EAGAIN) {
			PRINT_RESULT("mqtt_live", rc);
			return rc;
		} else if (rc == 0) {
			rc = mqtt_input(client);
			if (rc != 0) {
				PRINT_RESULT("mqtt_input", rc);
				return rc;
			}
		}

		remaining = timeout + start_time - k_uptime_get();
	}

	return 0;
}

/* In this routine we block until the connected variable is 1 */
static int try_to_connect(struct mqtt_client *client)
{
	int rc, i = 0;

	while (i++ < APP_CONNECT_TRIES && !connected) {

		client_init(client);

		rc = mqtt_connect(client);
		if (rc != 0) {
			PRINT_RESULT("mqtt_connect", rc);
			k_sleep(K_MSEC(APP_SLEEP_MSECS));
			continue;
		}

		prepare_fds(client);

		if (wait(APP_CONNECT_TIMEOUT_MS)) {
			mqtt_input(client);
		}

		if (!connected) {
			mqtt_abort(client);
		}
	}

	if (connected) {
		return 0;
	}

	return -EINVAL;
}


#define SUCCESS_OR_EXIT(rc) { if (rc != 0) { return 1; } }
#define SUCCESS_OR_BREAK(rc) { if (rc != 0) { break; } }

// Main publisher function
static int publisher(void)
{
	int i, rc, r = 0;

	include_topic = true;
	aliases_enabled = false;

	LOG_INF("attempting to connect: ");
	rc = try_to_connect(&client);
	PRINT_RESULT("try_to_connect", rc);
	SUCCESS_OR_EXIT(rc);

	i = 0;
	while (i++ < CONFIG_NET_SAMPLE_APP_MAX_ITERATIONS && connected) {
		r = -1;

		rc = mqtt_ping(&client);
		PRINT_RESULT("mqtt_ping", rc);
		SUCCESS_OR_BREAK(rc);

		rc = process_mqtt_and_sleep(&client, APP_SLEEP_MSECS);
		SUCCESS_OR_BREAK(rc);

		rc = publish(&client, MQTT_QOS_0_AT_MOST_ONCE);
		PRINT_RESULT("mqtt_publish", rc);
		SUCCESS_OR_BREAK(rc);

		rc = process_mqtt_and_sleep(&client, APP_SLEEP_MSECS);
		SUCCESS_OR_BREAK(rc);

		rc = publish(&client, MQTT_QOS_1_AT_LEAST_ONCE);
		PRINT_RESULT("mqtt_publish", rc);
		SUCCESS_OR_BREAK(rc);

		rc = process_mqtt_and_sleep(&client, APP_SLEEP_MSECS);
		SUCCESS_OR_BREAK(rc);

		rc = publish(&client, MQTT_QOS_2_EXACTLY_ONCE);
		PRINT_RESULT("mqtt_publish", rc);
		SUCCESS_OR_BREAK(rc);

		rc = process_mqtt_and_sleep(&client, APP_SLEEP_MSECS);
		SUCCESS_OR_BREAK(rc);

		r = 0;
	}

	rc = mqtt_disconnect(&client, NULL);
	PRINT_RESULT("mqtt_disconnect", rc);

	LOG_INF("Bye!");

	return r;
}

// Start the application
static int start_app(void)
{
	int r = 0, i = 0;

	while (!CONFIG_NET_SAMPLE_APP_MAX_CONNECTIONS ||
	       i++ < CONFIG_NET_SAMPLE_APP_MAX_CONNECTIONS) {
		r = publisher();

		if (!CONFIG_NET_SAMPLE_APP_MAX_CONNECTIONS) {
			k_sleep(K_MSEC(5000));
		}
	}

	return r;
}

// Wait for network interface to be up and get IPv4 address
static void wait_for_network(void)
{
    struct net_if *iface = net_if_get_default();
    int waited_ms = 0;

    LOG_INF("Waiting for network interface to be up...");
    while (!net_if_is_up(iface)) {
        k_sleep(K_MSEC(100));
    }

    LOG_INF("Network interface is up; starting DHCPv4...");
    net_dhcpv4_start(iface);

    /* Wait for IPv4 address with longer timeout */
    while (net_if_ipv4_get_global_addr(iface, NET_ADDR_PREFERRED) == NULL) {
        if (waited_ms >= 30000) {  // 30 second timeout
            LOG_ERR("Timed out waiting for IPv4 address");
            break;
        }
        k_sleep(K_MSEC(500));
        waited_ms += 500;
    }

    /* Additional wait after IP acquisition */
    k_sleep(K_MSEC(1000));

    const struct in_addr *addr = net_if_ipv4_get_global_addr(iface, NET_ADDR_PREFERRED);
    if (addr) {
        char buf[NET_IPV4_ADDR_LEN];
        net_addr_ntop(AF_INET, addr, buf, sizeof(buf));
        LOG_INF("IPv4 address: %s", buf);
    } else {
        LOG_ERR("No IPv4 address obtained");
    }
}

// Main function
int main(void)
{
    wait_for_network();

    int rc;

    rc = tls_init();
    PRINT_RESULT("tls_init", rc);

    rc = start_app();
    PRINT_RESULT("start_app", rc);

    // Loop forever - don't exit
    while (1) {
        k_sleep(K_SECONDS(1));
    }

    return 0;  // Never reached
}


// /* Flags set by the MQTT event handler */
// static volatile bool g_connack_ok;
// static volatile bool g_suback_ok;

// static void send_test_pub(struct mqtt_client *client);

// /* --- IPv4 helpers --- */
// static const struct in_addr *get_ipv4_addr(struct net_if *iface)
// {
//     return net_if_ipv4_get_global_addr(iface, NET_ADDR_PREFERRED);
// }

// static void print_ipv4(struct net_if *iface)
// {
//     char buf[NET_IPV4_ADDR_LEN];
//     const struct in_addr *addr = get_ipv4_addr(iface);

//     if (addr) {
//         LOG_INF("IPv4 address: %s", net_addr_ntop(AF_INET, addr, buf, sizeof(buf)));
//     } else {
//         LOG_INF("No IPv4 address yet");
//     }
// }

// static int acquire_dhcp_address(struct net_if *iface, int timeout_ms)
// {
//     int waited = 0;

//     net_dhcpv4_start(iface);

//     while (waited < timeout_ms) {
//         if (get_ipv4_addr(iface)) {
//             return 0;
//         }
//         k_sleep(K_MSEC(200));
//         waited += 200;
//     }
//     return -ETIMEDOUT;
// }

// /* --- MQTT event handler (v5) --- */
// static void mqtt_event_handler(struct mqtt_client *const client,
//                                const struct mqtt_evt *evt)
// {
//     switch (evt->type) {
//     case MQTT_EVT_CONNACK:
//         if (evt->param.connack.return_code == 0) {
//             LOG_INF("MQTT v5 connected");
//             g_connack_ok = true;
//         } else {
//             LOG_INF("MQTT CONNACK return_code=%u", evt->param.connack.return_code);
//         }
//         break;

//     case MQTT_EVT_PUBLISH: {
//         const struct mqtt_publish_param *p = &evt->param.publish;

//         LOG_INF("Message on topic %.*s (QoS %d, id %u)",
//                 (int)p->message.topic.topic.size,
//                 (const char *)p->message.topic.topic.utf8,
//                 p->message.topic.qos,
//                 p->message_id);

//         /* Drain payload fully */
//         size_t remaining = p->message.payload.len;
//         while (remaining > 0) {
//             uint8_t buf[64];
//             size_t to_read = MIN(remaining, sizeof(buf));
//             int r = mqtt_read_publish_payload(client, buf, to_read);
//             if (r < 0) {
//                 LOG_INF("mqtt_read_publish_payload err %d", r);
//                 break;
//             }
//             LOG_INF("Payload chunk (%d/%u): %.*s",
//                     r, (unsigned)p->message.payload.len, r, (const char *)buf);
//             remaining -= (size_t)r;
//         }

//         /* QoS1 inbound → send PUBACK */
//         if (p->message.topic.qos == MQTT_QOS_1_AT_LEAST_ONCE) {
//             struct mqtt_puback_param ack = { .message_id = p->message_id };
//             int err = mqtt_publish_qos1_ack(client, &ack);
//             if (err) {
//                 LOG_INF("PUBACK failed (%d)", err);
//             }
//         }
//         break;
//     }

//     case MQTT_EVT_SUBACK: {
//         const struct mqtt_suback_param *sa = &evt->param.suback;
//         LOG_INF("SUBACK id=%u count=%u",
//                 sa->message_id, (unsigned)sa->return_codes.len);
//         for (uint16_t i = 0; i < sa->return_codes.len; i++) {
//             uint8_t rc = sa->return_codes.data[i];
//             LOG_INF("  rc[%u]=%u", (unsigned)i, (unsigned)rc);
//         }
//         g_suback_ok = true;
//         break;
//     }

//     case MQTT_EVT_DISCONNECT:
//         LOG_INF("MQTT disconnected");
//         g_connack_ok = false;
//         g_suback_ok  = false;
//         break;

//     default:
//         break;
//     }
// }

// /* --- Configure client for MQTT v5 over TCP --- */
// static void mqtt_setup(struct mqtt_client *client, struct sockaddr_in *broker)
// {
//     mqtt_client_init(client);

//     memset(broker, 0, sizeof(*broker));
//     broker->sin_family = AF_INET;
//     broker->sin_port   = htons(BROKER_PORT);
//     int aerr = net_addr_pton(AF_INET, BROKER_IP, &broker->sin_addr);
//     if (aerr) {
//         LOG_INF("net_addr_pton failed (%d) for %s", aerr, BROKER_IP);
//     }

//     static uint8_t rxbuf[1024];
//     static uint8_t txbuf[1024];

//     client->broker           = (struct sockaddr *)broker;
//     client->evt_cb           = mqtt_event_handler;
//     client->client_id        = MQTT_UTF8_LITERAL(CLIENT_ID);

//     /* v5 protocol + clean start */
//     client->protocol_version = MQTT_VERSION_5_0;
//     client->clean_session    = 1;

//     client->keepalive        = CONFIG_MQTT_KEEPALIVE;
//     client->transport.type   = MQTT_TRANSPORT_NON_SECURE;

//     client->rx_buf           = rxbuf;
//     client->rx_buf_size      = sizeof(rxbuf);
//     client->tx_buf           = txbuf;
//     client->tx_buf_size      = sizeof(txbuf);

// #if defined(CONFIG_MQTT_VERSION_5_0)
//     /* Minimal non-empty CONNECT properties */
//     client->prop.request_problem_info = 1;
// #endif
// }

// /* Connect → wait CONNACK → subscribe → wait SUBACK */
// static int mqtt_connect_and_sub(struct mqtt_client *client, int timeout_ms)
// {
//     g_connack_ok = false;
//     g_suback_ok  = false;

//     int err = mqtt_connect(client);
//     if (err) {
//         LOG_INF("mqtt_connect failed (%d)", err);
//         return err;
//     }

//     /* Wait for CONNACK */
//     int waited = 0;
//     while (!g_connack_ok && waited < timeout_ms) {
//         err = mqtt_input(client);
//         if (err && err != -EAGAIN) {
//             int soerr = 0;
//             socklen_t slen = sizeof(soerr);
//             (void)zsock_getsockopt(client->transport.tcp.sock,
//                                    SOL_SOCKET, SO_ERROR, &soerr, &slen);
//             LOG_INF("mqtt_input while waiting CONNACK failed (%d), so_error=%d",
//                     err, soerr);
//             return err;
//         }
//         (void)mqtt_live(client);
//         k_sleep(K_MSEC(50));
//         waited += 50;
//     }
//     if (!g_connack_ok) {
//         LOG_INF("Timed out waiting for CONNACK");
//         return -ETIMEDOUT;
//     }

//     /* Subscribe after we are connected */
//     struct mqtt_topic topic = {
//         .topic = { .utf8 = SUB_TOPIC, .size = sizeof(SUB_TOPIC) - 1 },
//         .qos   = SUB_QOS,
//     };
//     const struct mqtt_subscription_list sub = {
//         .list       = &topic,
//         .list_count = 1U,
//         .message_id = 1U,
//     };

//     err = mqtt_subscribe(client, &sub);
//     if (err) {
//         LOG_INF("mqtt_subscribe failed (%d)", err);
//         return err;
//     }

//     /* Wait for SUBACK */
//     waited = 0;
//     while (!g_suback_ok && waited < timeout_ms) {
//         err = mqtt_input(client);
//         if (err && err != -EAGAIN) {
//             LOG_INF("mqtt_input while waiting SUBACK failed (%d)", err);
//             return err;
//         }
//         (void)mqtt_live(client);
//         k_sleep(K_MSEC(50));
//         waited += 50;
//     }
//     if (!g_suback_ok) {
//         LOG_INF("Timed out waiting for SUBACK");
//         return -ETIMEDOUT;
//     }

//     LOG_INF("Subscribed to %s (QoS %d)", SUB_TOPIC, SUB_QOS);

//     /* Send a test publish once after we’re subscribed */
//     send_test_pub(client);

//     return 0;
// }

// /* Regular service loop */
// static void mqtt_service_loop(struct mqtt_client *client)
// {
//     int64_t next_ping = k_uptime_get() + 1000;

//     for (;;) {
//         int err = mqtt_input(client);
//         if (err && err != -EAGAIN) {
//             LOG_INF("mqtt_input error %d; leaving service loop", err);
//             break;
//         }

//         if (k_uptime_get() >= next_ping) {
//             err = mqtt_live(client);
//             if (err && err != -EAGAIN) {
//                 LOG_INF("mqtt_live error %d; leaving service loop", err);
//                 break;
//             }
//             next_ping += 1000;
//         }

//         k_sleep(K_MSEC(50));
//     }
// }

// static void send_test_pub(struct mqtt_client *client)
// {
//     static uint8_t payload[] = "hi from nrf5340";

//     struct mqtt_publish_param pub = {
//         .message.topic = {
//             .topic = MQTT_UTF8_LITERAL("test/topic"),
//             .qos   = MQTT_QOS_1_AT_LEAST_ONCE,
//         },
//         .message.payload = {
//             .data = payload,
//             .len  = sizeof(payload) - 1,
//         },
//         .message_id = 42,
//         .dup_flag = 0,
//         .retain_flag = 0,
//     };
//     int err = mqtt_publish(client, &pub);
//     LOG_INF("publish: err=%d", err);
// }

// /* --- main --- */
// void main(void)
// {
//     LOG_INF("Booting: Ethernet (W5500) + DHCP + MQTT v5.0");

//     struct net_if *iface = net_if_get_default();
//     if (!iface) {
//         LOG_INF("No default net_if found!");
//         return;
//     }

//     if (acquire_dhcp_address(iface, 20000) == 0) {
//         print_ipv4(iface);
//     } else {
//         LOG_INF("DHCP timeout; check cable/router or try static IP.");
//         return;
//     }

//     struct mqtt_client client;
//     struct sockaddr_in broker;

//     mqtt_setup(&client, &broker);

//     if (mqtt_connect_and_sub(&client, 8000) == 0) {
//         mqtt_service_loop(&client);
//         (void)mqtt_disconnect(&client, NULL);
//     }
// }