/*
 * test_smoke — verifies the core links and the C ABI behaves as specified for M0.
 *
 * This is intentionally a behavior test, not a "does it compile" check: it asserts the
 * documented contract (version present, handle lifecycle, invalid-arg guards, and that
 * unimplemented calls report VC_ERR_NOT_IMPLEMENTED rather than crashing).
 */
#include <cstdio>
#include <cstring>

#include "voicecat.h"

static int g_failures = 0;

#define CHECK(cond)                                                       \
    do {                                                                  \
        if (!(cond)) {                                                    \
            std::printf("FAIL: %s (%s:%d)\n", #cond, __FILE__, __LINE__); \
            ++g_failures;                                                 \
        }                                                                 \
    } while (0)

int main() {
    // Version + result strings are always available.
    CHECK(vc_version_string() != nullptr);
    CHECK(std::strlen(vc_version_string()) > 0);
    CHECK(std::strcmp(vc_result_string(VC_OK), "ok") == 0);
    CHECK(std::strcmp(vc_result_string(VC_ERR_NOT_IMPLEMENTED), "not implemented") == 0);

    // Null-config create is rejected; valid create yields a handle.
    vc_callbacks cb{};
    CHECK(vc_client_create(nullptr, cb) == nullptr);

    vc_config cfg{};
    cfg.client_name = "test";
    cfg.client_version = "0";
    cfg.log_level = VC_LOG_OFF;
    vc_client* c = vc_client_create(&cfg, cb);
    CHECK(c != nullptr);

    // Invalid-arg guards on the ABI.
    CHECK(vc_connect(nullptr, "h", 1) == VC_ERR_INVALID_ARG);
    CHECK(vc_connect(c, nullptr, 1) == VC_ERR_INVALID_ARG);
    CHECK(vc_send_text(c, VC_TEXT_CHANNEL, 0, nullptr) == VC_ERR_INVALID_ARG);

    // Under skeleton preset: NOT_IMPLEMENTED. Under dev: VC_OK (async connect).
    vc_result rc_connect = vc_connect(c, "127.0.0.1", 8384);
    CHECK(rc_connect == VC_ERR_NOT_IMPLEMENTED || rc_connect == VC_OK);

    // Auth before connected (or on a stub) → NOT_CONNECTED or NOT_IMPLEMENTED.
    {
        vc_config cfg2 = cfg;
        vc_client* c2 = vc_client_create(&cfg2, cb);
        vc_result rc_auth = vc_authenticate_guest(c2, "nick");
        CHECK(rc_auth == VC_ERR_NOT_IMPLEMENTED || rc_auth == VC_ERR_NOT_CONNECTED);
        vc_client_destroy(c2);
    }

    // join_channel before connected → NOT_CONNECTED or NOT_IMPLEMENTED.
    vc_result rc_join = vc_join_channel(c, 1, nullptr);
    CHECK(rc_join == VC_ERR_NOT_IMPLEMENTED || rc_join == VC_ERR_NOT_CONNECTED);

    vc_device_list dl{};
    vc_result      rc_devices = vc_list_devices(c, VC_DEVICE_INPUT, &dl);
#ifdef VOICECAT_HAS_AUDIO
    // Real device enumeration is wired up once miniaudio is linked in (post-M3 follow-up).
    // Never assert count > 0 here — a headless CI build agent may legitimately report zero
    // audio devices; only that the call itself succeeded.
    CHECK(rc_devices == VC_OK);
#else
    CHECK(rc_devices == VC_ERR_NOT_IMPLEMENTED);
    CHECK(dl.count == 0);
#endif
    vc_free_device_list(&dl);

    vc_client_destroy(c);
    vc_client_destroy(nullptr);  // must be safe

    if (g_failures == 0) {
        std::printf("smoke: all checks passed\n");
        return 0;
    }
    std::printf("smoke: %d failure(s)\n", g_failures);
    return 1;
}
