/* =============================================================================
 * httpapi.c - HTTP POST 작성/전송 (이식성: 전송은 transport 콜백에 위임)
 * ===========================================================================*/
#include "httpapi.h"
#include "sig.h"
#include <string.h>

/* ── 경계 검사 어펜더 (httpapi 전용) ────────────────────────────────────── */
typedef struct { char *p; size_t cap; size_t len; int ok; } ha_buf;

static void ha_init(ha_buf *b, char *out, size_t cap)
{
    b->p = out; b->cap = cap; b->len = 0; b->ok = (cap > 0);
    if (b->ok) b->p[0] = '\0';
}
static void ha_putc(ha_buf *b, char c)
{
    if (!b->ok) return;
    if (b->len + 1 >= b->cap) { b->ok = 0; return; }
    b->p[b->len++] = c; b->p[b->len] = '\0';
}
static void ha_raw(ha_buf *b, const char *s) { while (*s) ha_putc(b, *s++); }
static void ha_u(ha_buf *b, unsigned long v)
{
    char tmp[20]; int n = 0;
    if (v == 0) { ha_putc(b, '0'); return; }
    while (v > 0 && n < (int)sizeof(tmp)) { tmp[n++] = (char)('0' + (v % 10)); v /= 10; }
    while (n > 0) ha_putc(b, tmp[--n]);
}

int http_build_post(char *out, size_t cap,
                    const char *host, const char *path,
                    const char *device_id, const char *sig_hex,
                    const char *body)
{
    ha_buf b;
    ha_init(&b, out, cap);

    ha_raw(&b, "POST ");          ha_raw(&b, path);  ha_raw(&b, " HTTP/1.1\r\n");
    ha_raw(&b, "Host: ");         ha_raw(&b, host);  ha_raw(&b, "\r\n");
    ha_raw(&b, "User-Agent: SHT30Sensor-STM32/" );  /* 버전은 본문 app_version 참고 */
    ha_raw(&b, "1.0\r\n");
    ha_raw(&b, "X-Device-Id: ");  ha_raw(&b, device_id);  ha_raw(&b, "\r\n");
    ha_raw(&b, "X-Signature: ");  ha_raw(&b, sig_hex);    ha_raw(&b, "\r\n");
    ha_raw(&b, "Content-Type: application/json\r\n");
    ha_raw(&b, "Content-Length: ");  ha_u(&b, (unsigned long)strlen(body));  ha_raw(&b, "\r\n");
    ha_raw(&b, "Connection: close\r\n");
    ha_raw(&b, "\r\n");
    ha_raw(&b, body);

    return b.ok ? (int)b.len : -1;
}

int http_parse_status(const uint8_t *resp, size_t len)
{
    /* "HTTP/1.1 200 OK..." 에서 상태 코드 추출 */
    size_t i = 0;
    /* 첫 공백까지 스킵 (HTTP/1.x) */
    while (i < len && resp[i] != ' ' && resp[i] != '\r' && resp[i] != '\n') i++;
    while (i < len && resp[i] == ' ') i++;
    if (i + 3 > len) return -1;
    if (resp[i] < '0' || resp[i] > '9') return -1;

    int code = 0, digits = 0;
    while (i < len && resp[i] >= '0' && resp[i] <= '9' && digits < 3) {
        code = code * 10 + (resp[i] - '0');
        i++; digits++;
    }
    return (digits == 3) ? code : -1;
}

int api_post_once(transport_t *t, const char *host, uint16_t port,
                  const char *path, const char *device_id,
                  const char *api_key, const char *body, uint32_t timeout_ms)
{
    char sig_hex[SIG_HEX_BUFSZ];
    char req[1024];
    uint8_t resp[256];

    sig_raw_body(api_key, body, strlen(body), sig_hex);

    int reqlen = http_build_post(req, sizeof(req), host, path, device_id, sig_hex, body);
    if (reqlen < 0) return -1000;   /* 요청 버퍼 부족 */

    int rc = t->connect(t->ctx, host, port, timeout_ms);
    if (rc < 0) return -2000 + rc;

    int sent = t->send(t->ctx, (const uint8_t *)req, (size_t)reqlen, timeout_ms);
    if (sent < 0) { t->close(t->ctx); return -3000 + sent; }

    /* 상태 라인을 포함하는 첫 응답까지만 읽는다(Connection: close). */
    size_t total = 0;
    int have_line = 0;
    while (total < sizeof(resp) - 1) {
        int n = t->recv(t->ctx, resp + total, sizeof(resp) - 1 - total, timeout_ms);
        if (n <= 0) break;                 /* 연결 종료 또는 오류 */
        total += (size_t)n;
        for (size_t k = 0; k < total; k++) { if (resp[k] == '\n') { have_line = 1; break; } }
        if (have_line) break;
    }
    t->close(t->ctx);

    if (total == 0) return -4000;          /* 응답 없음 */
    return http_parse_status(resp, total); /* HTTP 상태 코드 */
}
