#include "db.h"
#include "json.h"

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int parse_after_id(int *out) {
    const char *query = getenv("QUERY_STRING");
    const char *key = "after_id=";
    size_t key_len = strlen(key);
    *out = 0;

    if (query == NULL || query[0] == '\0') {
        return 1;
    }

    const char *p = query;
    while (*p != '\0') {
        if (strncmp(p, key, key_len) == 0) {
            p += key_len;
            break;
        }
        p = strchr(p, '&');
        if (p == NULL) {
            return 1;
        }
        p++;
    }

    if (*p == '\0') {
        return 0;
    }

    int value = 0;
    while (*p != '\0' && *p != '&') {
        if (!isdigit((unsigned char)*p)) {
            return 0;
        }
        value = value * 10 + (*p - '0');
        p++;
    }

    *out = value;
    return 1;
}

int main(void) {
    int after_id;
    Db db;
    SQLHSTMT stmt = SQL_NULL_HSTMT;
    SQLRETURN ret;
    SQLINTEGER after_value;
    SQLLEN after_ind = 0;

    SQLINTEGER id;
    SQLCHAR title[256];
    SQLCHAR body[4096];
    SQLCHAR created_at[32];
    SQLLEN id_ind, title_ind, body_ind, created_ind;
    int first = 1;

    if (!parse_after_id(&after_id)) {
        json_error_response("400 Bad Request", "after_id is invalid");
        return 0;
    }

    db_init(&db);
    if (!db_connect(&db)) {
        json_error_response("500 Internal Server Error", "database connection failed");
        return 1;
    }

    ret = SQLAllocHandle(SQL_HANDLE_STMT, db.dbc, &stmt);
    if (!odbc_succeeded(ret)) {
        json_error_response("500 Internal Server Error", "statement allocation failed");
        goto cleanup;
    }

    SQLCHAR sql[] =
        "SELECT id, title, body, created_at FROM diary "
        "WHERE is_public = 1 AND id > ? ORDER BY id ASC";
    after_value = after_id;

    ret = SQLPrepare(stmt, sql, SQL_NTS);
    if (odbc_succeeded(ret)) {
        ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &after_value, 0, &after_ind);
    }
    if (odbc_succeeded(ret)) {
        ret = SQLExecute(stmt);
    }
    if (!odbc_succeeded(ret)) {
        json_error_response("500 Internal Server Error", "query failed");
        goto cleanup;
    }

    printf("Content-Type: application/json; charset=UTF-8\r\n\r\n");
    printf("{\"items\":[");

    while ((ret = SQLFetch(stmt)) != SQL_NO_DATA) {
        if (!odbc_succeeded(ret)) {
            break;
        }
        SQLGetData(stmt, 1, SQL_C_SLONG, &id, 0, &id_ind);
        SQLGetData(stmt, 2, SQL_C_CHAR, title, sizeof(title), &title_ind);
        SQLGetData(stmt, 3, SQL_C_CHAR, body, sizeof(body), &body_ind);
        SQLGetData(stmt, 4, SQL_C_CHAR, created_at, sizeof(created_at), &created_ind);

        if (!first) {
            printf(",");
        }
        first = 0;

        printf("{\"id\":%d,\"title\":\"", id);
        json_escape_print(stdout, (const char *)title);
        printf("\",\"body\":\"");
        json_escape_print(stdout, (const char *)body);
        printf("\",\"created_at\":\"");
        json_escape_print(stdout, (const char *)created_at);
        printf("\"}");
    }

    printf("]}\n");

cleanup:
    if (stmt != SQL_NULL_HSTMT) {
        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
    }
    db_close(&db);
    return 0;
}
