/**
 * @file database.c
 * @brief Synor Database SDK implementation
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "synor/database.h"

/* Forward declarations from common.c */
typedef struct synor_http_client synor_http_client_t;
synor_http_client_t* synor_http_client_create(
    const char* api_key, const char* endpoint,
    uint32_t timeout_ms, uint32_t retries, bool debug);
void synor_http_client_destroy(synor_http_client_t* client);
synor_error_t synor_http_get(synor_http_client_t* client, const char* path,
    char** response, size_t* response_size);
synor_error_t synor_http_post(synor_http_client_t* client, const char* path,
    const char* body, char** response, size_t* response_size);
synor_error_t synor_http_put(synor_http_client_t* client, const char* path,
    const char* body, char** response, size_t* response_size);
synor_error_t synor_http_delete(synor_http_client_t* client, const char* path,
    char** response, size_t* response_size);
char* synor_strdup(const char* s);
char* synor_url_encode(const char* s);

/* Internal database structure */
struct synor_database {
    synor_http_client_t* http;
    bool closed;
};

synor_database_t* synor_database_create(const synor_db_config_t* config) {
    if (!config || !config->api_key) {
        return NULL;
    }

    synor_database_t* db = calloc(1, sizeof(synor_database_t));
    if (!db) return NULL;

    const char* endpoint = config->endpoint ?
        config->endpoint : "https://db.synor.io/v1";
    uint32_t timeout = config->timeout_ms > 0 ? config->timeout_ms : 60000;
    uint32_t retries = config->retries > 0 ? config->retries : 3;

    db->http = synor_http_client_create(
        config->api_key, endpoint, timeout, retries, config->debug);

    if (!db->http) {
        free(db);
        return NULL;
    }

    db->closed = false;
    return db;
}

void synor_database_destroy(synor_database_t* db) {
    if (!db) return;
    db->closed = true;
    synor_http_client_destroy(db->http);
    free(db);
}

bool synor_database_is_closed(synor_database_t* db) {
    return db ? db->closed : true;
}

bool synor_database_health_check(synor_database_t* db) {
    if (!db || db->closed) return false;

    char* response = NULL;
    size_t response_size = 0;

    if (synor_http_get(db->http, "/health", &response, &response_size) != 0) {
        return false;
    }

    bool healthy = response && strstr(response, "\"healthy\"") != NULL;
    free(response);
    return healthy;
}

/* ==================== Key-Value Operations ==================== */

synor_db_error_t synor_kv_get(synor_database_t* db, const char* key, char** value) {
    if (!db || db->closed) return SYNOR_DB_ERROR_CLIENT_CLOSED;
    if (!key || !value) return SYNOR_DB_ERROR_UNKNOWN;

    char* encoded_key = synor_url_encode(key);
    if (!encoded_key) return SYNOR_DB_ERROR_MEMORY;

    char path[512];
    snprintf(path, sizeof(path), "/kv/%s", encoded_key);
    free(encoded_key);

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_get(db->http, path, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_DB_ERROR_HTTP;
    }

    /* Parse JSON response to extract value - simplified */
    *value = response;
    return SYNOR_DB_OK;
}

synor_db_error_t synor_kv_set(synor_database_t* db, const char* key,
    const char* value, int32_t ttl) {
    if (!db || db->closed) return SYNOR_DB_ERROR_CLIENT_CLOSED;
    if (!key || !value) return SYNOR_DB_ERROR_UNKNOWN;

    char* encoded_key = synor_url_encode(key);
    if (!encoded_key) return SYNOR_DB_ERROR_MEMORY;

    char path[512];
    snprintf(path, sizeof(path), "/kv/%s", encoded_key);
    free(encoded_key);

    char body[4096];
    if (ttl > 0) {
        snprintf(body, sizeof(body), "{\"key\":\"%s\",\"value\":%s,\"ttl\":%d}",
            key, value, ttl);
    } else {
        snprintf(body, sizeof(body), "{\"key\":\"%s\",\"value\":%s}", key, value);
    }

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_put(db->http, path, body, &response, &response_size);
    free(response);

    return err == 0 ? SYNOR_DB_OK : SYNOR_DB_ERROR_HTTP;
}

synor_db_error_t synor_kv_delete(synor_database_t* db, const char* key) {
    if (!db || db->closed) return SYNOR_DB_ERROR_CLIENT_CLOSED;
    if (!key) return SYNOR_DB_ERROR_UNKNOWN;

    char* encoded_key = synor_url_encode(key);
    if (!encoded_key) return SYNOR_DB_ERROR_MEMORY;

    char path[512];
    snprintf(path, sizeof(path), "/kv/%s", encoded_key);
    free(encoded_key);

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_delete(db->http, path, &response, &response_size);
    free(response);

    return err == 0 ? SYNOR_DB_OK : SYNOR_DB_ERROR_HTTP;
}

synor_db_error_t synor_kv_list(synor_database_t* db, const char* prefix,
    synor_kv_list_t* result) {
    (void)db; (void)prefix; (void)result;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

void synor_kv_list_free(synor_kv_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        free(list->items[i].key);
        free(list->items[i].value);
    }
    free(list->items);
    list->items = NULL;
    list->count = 0;
}

/* ==================== Document Operations ==================== */

synor_db_error_t synor_doc_create(synor_database_t* db, const char* collection,
    const char* document, char** id) {
    if (!db || db->closed) return SYNOR_DB_ERROR_CLIENT_CLOSED;
    if (!collection || !document || !id) return SYNOR_DB_ERROR_UNKNOWN;

    char* encoded = synor_url_encode(collection);
    if (!encoded) return SYNOR_DB_ERROR_MEMORY;

    char path[512];
    snprintf(path, sizeof(path), "/collections/%s/documents", encoded);
    free(encoded);

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_post(db->http, path, document, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_DB_ERROR_HTTP;
    }

    /* Parse response to extract id - simplified */
    *id = response;
    return SYNOR_DB_OK;
}

synor_db_error_t synor_doc_get(synor_database_t* db, const char* collection,
    const char* id, synor_document_t* result) {
    (void)db; (void)collection; (void)id; (void)result;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

synor_db_error_t synor_doc_update(synor_database_t* db, const char* collection,
    const char* id, const char* update) {
    (void)db; (void)collection; (void)id; (void)update;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

synor_db_error_t synor_doc_delete(synor_database_t* db, const char* collection,
    const char* id) {
    (void)db; (void)collection; (void)id;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

synor_db_error_t synor_doc_query(synor_database_t* db, const char* collection,
    const synor_document_query_t* query, synor_document_list_t* result) {
    (void)db; (void)collection; (void)query; (void)result;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

void synor_document_free(synor_document_t* doc) {
    if (!doc) return;
    free(doc->id);
    free(doc->collection);
    free(doc->data);
    doc->id = NULL;
    doc->collection = NULL;
    doc->data = NULL;
}

void synor_document_list_free(synor_document_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_document_free(&list->documents[i]);
    }
    free(list->documents);
    list->documents = NULL;
    list->count = 0;
}

/* ==================== Vector Operations ==================== */

synor_db_error_t synor_vector_upsert(synor_database_t* db, const char* collection,
    const synor_vector_entry_t* vectors, size_t count) {
    (void)db; (void)collection; (void)vectors; (void)count;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

synor_db_error_t synor_vector_search(synor_database_t* db, const char* collection,
    const double* vector, size_t vector_size, int32_t k,
    synor_search_result_list_t* result) {
    (void)db; (void)collection; (void)vector; (void)vector_size; (void)k; (void)result;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

synor_db_error_t synor_vector_delete(synor_database_t* db, const char* collection,
    const char** ids, size_t count) {
    (void)db; (void)collection; (void)ids; (void)count;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

void synor_search_result_list_free(synor_search_result_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        free(list->results[i].id);
        free(list->results[i].vector);
        free(list->results[i].metadata);
    }
    free(list->results);
    list->results = NULL;
    list->count = 0;
}

/* ==================== Time Series Operations ==================== */

synor_db_error_t synor_ts_write(synor_database_t* db, const char* series,
    const synor_data_point_t* points, size_t count) {
    (void)db; (void)series; (void)points; (void)count;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

synor_db_error_t synor_ts_query(synor_database_t* db, const char* series,
    const synor_time_range_t* range, const synor_aggregation_t* aggregation,
    synor_data_point_list_t* result) {
    (void)db; (void)series; (void)range; (void)aggregation; (void)result;
    return SYNOR_DB_ERROR_UNKNOWN; /* TODO: Implement */
}

void synor_data_point_list_free(synor_data_point_list_t* list) {
    if (!list) return;
    free(list->points);
    list->points = NULL;
    list->count = 0;
}
