#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "usage.h"

static void check(int condition, const char *msg) {
    if (!condition) {
        fprintf(stderr, "FAIL: %s\n", msg);
        exit(1);
    }
}

static char *read_file(const char *path) {
    FILE *f = fopen(path, "rb");
    if (!f) return NULL;
    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    fseek(f, 0, SEEK_SET);
    char *buffer = malloc((size_t)size + 1);
    fread(buffer, 1, (size_t)size, f);
    buffer[size] = '\0';
    fclose(f);
    return buffer;
}

static char *wrap_response_json(const char *body) {
    size_t body_len = strlen(body);
    size_t cap = body_len * 2 + 64;
    char *out = malloc(cap);
    strcpy(out, "[{\"status\":200,\"body\":\"");
    size_t pos = strlen(out);
    for (size_t i = 0; i < body_len; i++) {
        char c = body[i];
        if (c == '"') {
            out[pos++] = '\\';
            out[pos++] = '"';
        } else if (c == '\\') {
            out[pos++] = '\\';
            out[pos++] = '\\';
        } else if (c == '\n') {
            out[pos++] = '\\';
            out[pos++] = 'n';
        } else if (c == '\r') {
            out[pos++] = '\\';
            out[pos++] = 'r';
        } else if (c == '\t') {
            out[pos++] = '\\';
            out[pos++] = 't';
        } else {
            out[pos++] = c;
        }
    }
    out[pos++] = '"';
    out[pos++] = '}';
    out[pos++] = ']';
    out[pos] = '\0';
    return out;
}

int main(int argc, char **argv) {
    if (argc < 2) return 2;

    check(usage_abi_version() == 4, "ABI version must be 4");

    char *providers = usage_providers();
    check(providers != NULL, "providers must not be NULL");
    check(strstr(providers, "\"provider\":\"openai-codex\"") != NULL, "codex provider present");
    check(strstr(providers, "\"provider\":\"hyper\"") != NULL, "hyper provider present");
    usage_free(providers);

    char *body = read_file(argv[1]);
    check(body != NULL, "cannot read fixture file");

    /* 1. Codex step 1: asks for request */
    const char *cred = "{\"kind\":\"oauth\",\"access\":\"tok\",\"email\":\"user@example.com\"}";
    char *first_step = usage_advance(NULL, "openai-codex", strlen("openai-codex"), cred, strlen(cred), "[]", 2, 0);
    check(first_step != NULL, "first step should not be NULL");
    check(strstr(first_step, "\"url\":\"https://chatgpt.com/backend-api/wham/usage\"") != NULL, "codex url");
    check(strstr(first_step, "\"kind\":\"http\"") != NULL, "codex request kind http");
    usage_free(first_step);

    /* 2. Codex step 2: drives recorded body from argv[1] (codex-usage-live.json) */
    char *resp_json = wrap_response_json(body);
    char *report = usage_advance(NULL, "openai-codex", strlen("openai-codex"), cred, strlen(cred), resp_json, strlen(resp_json), 1789514000000LL);
    check(report != NULL, "report should not be NULL");
    check(strstr(report, "\"planType\":\"prolite\"") != NULL, "codex planType prolite");
    check(strstr(report, "\"label\":\"Primary\"") != NULL, "codex Primary limit");
    check(strstr(report, "\"status\":\"exhausted\"") != NULL, "codex exhausted status");
    check(strstr(report, "\"email\":\"user@example.com\"") != NULL, "codex email");
    usage_free(report);
    free(resp_json);
    free(body);

    /* 3. Hyper multi-round state test: team id and name survive across rounds */
    usage_state *state = usage_state_new();
    check(state != NULL, "usage_state_new failed");

    const char *hyper_cred = "{\"kind\":\"apiKey\",\"apiKey\":\"sk-hyper-test\"}";
    const char *teams_resp = "[{\"status\":200,\"body\":\"{\\\"items\\\":[{\\\"id\\\":\\\"team_live_1\\\",\\\"name\\\":\\\"Smoke Team\\\"}]}\"}]";
    char *hyper_step1 = usage_advance(state, "hyper", strlen("hyper"), hyper_cred, strlen(hyper_cred), teams_resp, strlen(teams_resp), 0);
    check(hyper_step1 != NULL, "hyper round 1 should succeed");
    check(strstr(hyper_step1, "team_live_1/billing") != NULL, "hyper asked for billing");
    usage_free(hyper_step1);

    const char *billing_resp = "[{\"status\":200,\"body\":\"{\\\"status\\\":\\\"active\\\",\\\"plan\\\":{\\\"name\\\":\\\"Shred\\\",\\\"hypercredits\\\":100}}\"},{\"status\":200,\"body\":\"{\\\"items\\\":[]}\"}]";
    char *hyper_step2 = usage_advance(state, "hyper", strlen("hyper"), hyper_cred, strlen(hyper_cred), billing_resp, strlen(billing_resp), 0);
    check(hyper_step2 != NULL, "hyper round 2 should succeed");
    check(strstr(hyper_step2, "\"accountId\":\"team_live_1\"") != NULL, "hyper preserved team_id");
    check(strstr(hyper_step2, "Team: Smoke Team") != NULL, "hyper preserved team_name");
    usage_free(hyper_step2);

    usage_state_free(state);

    /* 4. Hyper round 2 with NULL state: does not crash, but cannot emit team name */
    char *hyper_no_state = usage_advance(NULL, "hyper", strlen("hyper"), hyper_cred, strlen(hyper_cred), billing_resp, strlen(billing_resp), 0);
    check(hyper_no_state != NULL, "hyper with NULL state should not crash");
    check(strstr(hyper_no_state, "Team: Smoke Team") == NULL, "without state, team name is absent");
    usage_free(hyper_no_state);

    /* 5. Unknown provider */
    char *unknown = usage_advance(NULL, "nonexistent", strlen("nonexistent"), cred, strlen(cred), "[]", 2, 0);
    check(unknown != NULL && strstr(unknown, "unknown provider") != NULL, "unknown provider handled");
    usage_free(unknown);

    /* 6. Null-safe advance */
    char *none = usage_advance(NULL, NULL, 0, NULL, 0, NULL, 0, 0);
    check(none != NULL && strstr(none, "unknown provider") != NULL, "null provider handled safely");
    usage_free(none);

    usage_free(NULL);
    usage_state_free(NULL);

    printf("c_smoke: all assertions passed\n");
    return 0;
}
