#include "cgi.h"
#include "db.h"
#include "form.h"
#include "session.h"

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

#define MAX_ITEMS 16
#define MAX_POST 16384

static int valid_input(const char *title, const char *body, const char *pub) {
    if (title == NULL || body == NULL || pub == NULL) {
        return 0;
    }
    if (title[0] == '\0' || body[0] == '\0') {
        return 0;
    }
    if (strlen(title) > 255 || strlen(body) > 10000) {
        return 0;
    }
    return strcmp(pub, "0") == 0 || strcmp(pub, "1") == 0;
}

int main(void) {
    Session session;
    FormItem items[MAX_ITEMS];
    char *post = NULL;
    Db db;
    SQLHSTMT stmt = SQL_NULL_HSTMT;
    SQLRETURN ret = SQL_ERROR;

    if (!session_load(&session)) {
        cgi_redirect("/login.html");
        return 0;
    }

    if (!cgi_read_post_body(&post, MAX_POST)) {
        cgi_status_header("400 Bad Request", "text/plain");
        printf("invalid post body\n");
        return 0;
    }

    int count = form_parse(post, items, MAX_ITEMS);
    const char *title = form_get(items, count, "title");
    const char *body = form_get(items, count, "body");
    const char *pub = form_get(items, count, "is_public");

    if (!valid_input(title, body, pub)) {
        cgi_status_header("400 Bad Request", "text/plain");
        printf("invalid input\n");
        goto cleanup_form;
    }

    db_init(&db);
    if (!db_connect(&db)) {
        cgi_status_header("500 Internal Server Error", "text/plain");
        printf("database connection failed\n");
        goto cleanup_form;
    }

    ret = SQLAllocHandle(SQL_HANDLE_STMT, db.dbc, &stmt);
    if (!odbc_succeeded(ret)) {
        cgi_status_header("500 Internal Server Error", "text/plain");
        goto cleanup_db;
    }

    SQLCHAR sql[] = "INSERT INTO diary (user_id, title, body, is_public) VALUES (?, ?, ?, ?)";
    SQLINTEGER user_id = session.user_id;
    SQLINTEGER is_public = strcmp(pub, "1") == 0 ? 1 : 0;
    SQLLEN user_id_ind = 0;
    SQLLEN title_ind = SQL_NTS;
    SQLLEN body_ind = SQL_NTS;
    SQLLEN public_ind = 0;

    ret = SQLPrepare(stmt, sql, SQL_NTS);
    if (!odbc_succeeded(ret)) {
        cgi_status_header("500 Internal Server Error", "text/plain");
        goto cleanup_db;
    }

    ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &user_id, 0, &user_id_ind);
    if (odbc_succeeded(ret)) ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 255, 0, (SQLPOINTER)title, 0, &title_ind);
    if (odbc_succeeded(ret)) ret = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, 0, 0, (SQLPOINTER)body, 0, &body_ind);
    if (odbc_succeeded(ret)) ret = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &is_public, 0, &public_ind);
    if (!odbc_succeeded(ret)) {
        cgi_status_header("500 Internal Server Error", "text/plain");
        goto cleanup_db;
    }

    ret = SQLExecute(stmt);
    if (!odbc_succeeded(ret)) {
        cgi_status_header("500 Internal Server Error", "text/plain");
        printf("insert failed\n");
        goto cleanup_db;
    }

    cgi_redirect("/cgi-bin/diary_list.cgi");

cleanup_db:
    if (stmt != SQL_NULL_HSTMT) {
        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
    }
    db_close(&db);
cleanup_form:
    form_free(items, count);
    free(post);
    return 0;
}
