#include "http.h"
#include "net.h"
#include "tls.h"
#include "arch.h"
#include "fb.h"
#include "util.h"

char html_buf[HTML_BUF_SIZE];
uint32_t html_len = 0;

int http_get(const char *host, const char *path, char *body, uint32_t max_body)
{
    uint8_t ip[4];
    fb_printf("Resolving %s...\n", host);
    if(dns_resolve(host, ip) < 0) {
        fb_printf("DNS failed for %s\n", host);
        return -1;
    }
    fb_printf("IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);

    fb_printf("Connecting to %d.%d.%d.%d:80...\n", ip[0], ip[1], ip[2], ip[3]);
    if(tcp_connect(ip, 80) < 0) {
        fb_printf("TCP connect failed\n");
        return -1;
    }
    fb_printf("Connected!\n");

    char req[512];
    int rlen = 0;
    const char *p = "GET ";
    while(*p) req[rlen++] = *p++;
    p = path;
    while(*p) req[rlen++] = *p++;
    p = " HTTP/1.0\r\nHost: ";
    while(*p) req[rlen++] = *p++;
    p = host;
    while(*p) req[rlen++] = *p++;
    p = "\r\nConnection: close\r\n\r\n";
    while(*p) req[rlen++] = *p++;
    req[rlen] = '\0';

    fb_printf("Sending request...\n");
    tcp_send(req, rlen);

    uint32_t total = 0;
    char buf[4096];
    uint64_t start = rdtsc();

    while(total < max_body - 1) {
        if(rdtsc() - start > 4000000000ULL) break;
        int n = tcp_recv(buf, sizeof(buf) - 1, 50);
        if(n > 0) {
            buf[n] = '\0';
            uint32_t copy = (uint32_t)n;
            if(total + copy > max_body - 1) copy = max_body - 1 - total;
            memcpy(body + total, buf, copy);
            total += copy;
            start = rdtsc();
        } else if(n == 0) {
            continue;
        } else {
            break;
        }
    }
    body[total] = '\0';

    tcp_close();

    char *hdr_end = NULL;
    for(uint32_t i = 0; i + 3 < total; i++) {
        if(body[i] == '\r' && body[i+1] == '\n' &&
           body[i+2] == '\r' && body[i+3] == '\n') {
            hdr_end = body + i + 4;
            break;
        }
    }

    if(hdr_end) {
        uint32_t hdr_len = (uint32_t)(hdr_end - body);
        uint32_t body_len = total - hdr_len;
        memmove(body, hdr_end, body_len);
        body[body_len] = '\0';
        total = body_len;
    }

    /* Save to global buffer for less viewer */
    if(total > 0 && total < HTML_BUF_SIZE) {
        memcpy(html_buf, body, total);
        html_buf[total] = '\0';
        html_len = total;
    }

    return (int)total;
}

int http_post(const char *host, const char *path, const char *content_type,
              const char *data, uint32_t data_len,
              char *body, uint32_t max_body)
{
    uint8_t ip[4];
    fb_printf("Resolving %s...\n", host);
    if(dns_resolve(host, ip) < 0) {
        fb_printf("DNS failed for %s\n", host);
        return -1;
    }
    fb_printf("IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);

    fb_printf("Connecting to %d.%d.%d.%d:80...\n", ip[0], ip[1], ip[2], ip[3]);
    if(tcp_connect(ip, 80) < 0) {
        fb_printf("TCP connect failed\n");
        return -1;
    }
    fb_printf("Connected!\n");

    char req[1024];
    int rlen = 0;

    const char *p = "POST ";
    while(*p) req[rlen++] = *p++;
    p = path;
    while(*p) req[rlen++] = *p++;
    p = " HTTP/1.0\r\nHost: ";
    while(*p) req[rlen++] = *p++;
    p = host;
    while(*p) req[rlen++] = *p++;
    p = "\r\nContent-Type: ";
    while(*p) req[rlen++] = *p++;
    p = content_type;
    while(*p) req[rlen++] = *p++;
    p = "\r\nContent-Length: ";
    while(*p) req[rlen++] = *p++;

    char clen_str[16];
    int clen_len = 0;
    uint32_t tmp = data_len;
    if(tmp == 0) clen_str[clen_len++] = '0';
    else {
        char rev[10];
        int ri = 0;
        while(tmp) { rev[ri++] = '0' + (tmp % 10); tmp /= 10; }
        while(ri--) clen_str[clen_len++] = rev[ri];
    }
    for(int i = 0; i < clen_len; i++) req[rlen++] = clen_str[i];

    p = "\r\nConnection: close\r\n\r\n";
    while(*p) req[rlen++] = *p++;

    for(uint32_t i = 0; i < data_len && rlen < 1020; i++)
        req[rlen++] = data[i];

    req[rlen] = '\0';

    fb_printf("Sending POST request (%d bytes)...\n", rlen);
    tcp_send(req, rlen);

    uint32_t total = 0;
    char buf[4096];
    uint64_t start = rdtsc();

    while(total < max_body - 1) {
        if(rdtsc() - start > 4000000000ULL) break;
        int n = tcp_recv(buf, sizeof(buf) - 1, 50);
        if(n > 0) {
            buf[n] = '\0';
            uint32_t copy = (uint32_t)n;
            if(total + copy > max_body - 1) copy = max_body - 1 - total;
            memcpy(body + total, buf, copy);
            total += copy;
            start = rdtsc();
        } else if(n == 0) {
            continue;
        } else {
            break;
        }
    }
    body[total] = '\0';

    tcp_close();

    char *hdr_end = NULL;
    for(uint32_t i = 0; i + 3 < total; i++) {
        if(body[i] == '\r' && body[i+1] == '\n' &&
           body[i+2] == '\r' && body[i+3] == '\n') {
            hdr_end = body + i + 4;
            break;
        }
    }

    if(hdr_end) {
        uint32_t hdr_len = (uint32_t)(hdr_end - body);
        uint32_t body_len = total - hdr_len;
        memmove(body, hdr_end, body_len);
        body[body_len] = '\0';
        total = body_len;
    }

    if(total > 0 && total < HTML_BUF_SIZE) {
        memcpy(html_buf, body, total);
        html_buf[total] = '\0';
        html_len = total;
    }

    return (int)total;
}
