/* Minimal out-of-tree CitusIO Bridge SDK adapter.
 *
 * This file includes only the installed public SDK header and standard/POSIX
 * C headers. It appends one non-secret event summary per accepted delivery to
 * a file:// endpoint, making the full path easy to inspect.
 */

#include "nginz_iot_bridge_sdk.h"

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

struct hello_world_state {
    char output_path[NGINZ_IOT_BRIDGE_SDK_MAX_CONFIG];
    int connected;
};

static int hello_error(char *error, size_t error_len, const char *reason) {
    size_t length;
    if (error == NULL || error_len == 0) return 1;
    length = strlen(reason);
    if (length >= error_len) length = error_len - 1;
    memcpy(error, reason, length);
    error[length] = '\0';
    return 1;
}

static int hello_write(const char *path, const char *text, size_t text_len) {
    int fd;
    size_t offset = 0;
    fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0600);
    if (fd < 0) return 1;
    while (offset < text_len) {
        ssize_t written = write(fd, text + offset, text_len - offset);
        if (written <= 0) {
            (void)close(fd);
            return 1;
        }
        offset += (size_t)written;
    }
    return close(fd) == 0 ? 0 : 1;
}

static int hello_init(
    struct nginz_iot_bridge_sdk_adapter *adapter,
    const struct nginz_iot_bridge_sdk_config *config,
    char *error,
    size_t error_len
) {
    static const char prefix[] = "file://";
    struct hello_world_state *state;
    const char *path;
    size_t path_len;
    if (adapter == NULL || config == NULL) return hello_error(error, error_len, "null_config");
    if (config->abi_version != NGINZ_IOT_BRIDGE_SDK_ABI_VERSION_V1 ||
        nginz_iot_bridge_sdk_check_capabilities_v1(config->capabilities) != 0) {
        return hello_error(error, error_len, "unsupported_contract");
    }
    if (strncmp(config->endpoint, prefix, sizeof(prefix) - 1) != 0) {
        return hello_error(error, error_len, "file_endpoint_required");
    }
    path = config->endpoint + sizeof(prefix) - 1;
    path_len = strlen(path);
    if (path_len == 0 || path_len >= sizeof(state->output_path)) {
        return hello_error(error, error_len, "invalid_output_path");
    }
    state = (struct hello_world_state *)calloc(1, sizeof(*state));
    if (state == NULL) return hello_error(error, error_len, "allocation_failed");
    memcpy(state->output_path, path, path_len + 1);
    adapter->abi_version = NGINZ_IOT_BRIDGE_SDK_ABI_VERSION_V1;
    adapter->capabilities = NGINZ_IOT_BRIDGE_SDK_CAP_REQUIRED_SINK_V1;
    adapter->user_data = state;
    return 0;
}

static int hello_connect(
    struct nginz_iot_bridge_sdk_adapter *adapter,
    char *error,
    size_t error_len
) {
    struct hello_world_state *state;
    if (adapter == NULL || adapter->user_data == NULL) {
        return hello_error(error, error_len, "not_initialized");
    }
    state = (struct hello_world_state *)adapter->user_data;
    state->connected = 1;
    return 0;
}

static int hello_send(
    struct nginz_iot_bridge_sdk_adapter *adapter,
    const struct nginz_iot_bridge_sdk_event *event,
    const uint8_t *payload,
    size_t payload_len,
    struct nginz_iot_bridge_sdk_result *out
) {
    struct hello_world_state *state;
    char line[512];
    int line_len;
    (void)payload;
    if (adapter == NULL || event == NULL || out == NULL) return 1;
    memset(out, 0, sizeof(*out));
    out->abi_version = NGINZ_IOT_BRIDGE_SDK_ABI_VERSION_V1;
    state = (struct hello_world_state *)adapter->user_data;
    if (state == NULL || !state->connected) {
        out->failure_class = NGINZ_IOT_BRIDGE_SDK_RETRYABLE;
        (void)snprintf(out->reason, sizeof(out->reason), "hello_not_connected");
        return 0;
    }
    line_len = snprintf(
        line,
        sizeof(line),
        "hello-world event_seq=%llu topic=%.*s payload_bytes=%zu\n",
        (unsigned long long)event->event_seq,
        (int)event->topic_len,
        event->topic,
        payload_len
    );
    if (line_len < 0 || (size_t)line_len >= sizeof(line) ||
        hello_write(state->output_path, line, (size_t)line_len) != 0) {
        out->failure_class = NGINZ_IOT_BRIDGE_SDK_RETRYABLE;
        (void)snprintf(out->reason, sizeof(out->reason), "hello_write_failed");
        return 0;
    }
    out->failure_class = NGINZ_IOT_BRIDGE_SDK_SUCCESS;
    (void)snprintf(out->reason, sizeof(out->reason), "hello_delivered");
    return 0;
}

static int hello_flush(
    struct nginz_iot_bridge_sdk_adapter *adapter,
    char *error,
    size_t error_len
) {
    if (adapter == NULL || adapter->user_data == NULL) {
        return hello_error(error, error_len, "not_initialized");
    }
    return 0;
}

static int hello_drain(
    struct nginz_iot_bridge_sdk_adapter *adapter,
    char *error,
    size_t error_len
) {
    static const char marker[] = "hello-world drained=true\n";
    struct hello_world_state *state;
    if (adapter == NULL || adapter->user_data == NULL) {
        return hello_error(error, error_len, "not_initialized");
    }
    state = (struct hello_world_state *)adapter->user_data;
    if (hello_write(state->output_path, marker, sizeof(marker) - 1) != 0) {
        return hello_error(error, error_len, "drain_write_failed");
    }
    return 0;
}

static void hello_close(struct nginz_iot_bridge_sdk_adapter *adapter) {
    if (adapter == NULL) return;
    free(adapter->user_data);
    adapter->user_data = NULL;
}

static size_t hello_redact(
    struct nginz_iot_bridge_sdk_adapter *adapter,
    char *out,
    size_t out_len
) {
    static const char redacted[] = "hello-world endpoint=<redacted>";
    size_t length = sizeof(redacted) - 1;
    (void)adapter;
    if (out == NULL || out_len == 0) return 0;
    if (length >= out_len) length = out_len - 1;
    memcpy(out, redacted, length);
    out[length] = '\0';
    return length;
}

static const struct nginz_iot_bridge_sdk_vtable hello_world_vtable = {
    .abi_version = NGINZ_IOT_BRIDGE_SDK_ABI_VERSION_V1,
    .capabilities = NGINZ_IOT_BRIDGE_SDK_CAP_REQUIRED_SINK_V1,
    .name = "hello-world",
    .init = hello_init,
    .connect = hello_connect,
    .send = hello_send,
    .flush = hello_flush,
    .drain = hello_drain,
    .close = hello_close,
    .redact_config = hello_redact,
};

const struct nginz_iot_bridge_sdk_vtable *nginz_iot_bridge_sdk_vtable(void) {
    return &hello_world_vtable;
}
