/**
 * @file storage.c
 * @brief Synor Storage SDK implementation
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "synor/storage.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);
char* synor_strdup(const char* s);

/* Internal storage structure */
struct synor_storage {
    synor_http_client_t* http;
    char* gateway;
};

synor_storage_t* synor_storage_create(const synor_storage_config_t* config) {
    if (!config || !config->api_key) {
        return NULL;
    }

    synor_storage_t* storage = calloc(1, sizeof(synor_storage_t));
    if (!storage) return NULL;

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

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

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

    storage->gateway = synor_strdup(gateway);

    return storage;
}

void synor_storage_destroy(synor_storage_t* storage) {
    if (!storage) return;
    synor_http_client_destroy(storage->http);
    free(storage->gateway);
    free(storage);
}

char* synor_storage_get_gateway_url(synor_storage_t* storage,
    const char* cid, const char* path) {
    if (!storage || !cid) return NULL;

    size_t len = strlen(storage->gateway) + strlen("/ipfs/") + strlen(cid);
    if (path) {
        len += 1 + strlen(path);
    }
    len += 1; /* null terminator */

    char* url = malloc(len);
    if (!url) return NULL;

    if (path) {
        snprintf(url, len, "%s/ipfs/%s/%s", storage->gateway, cid, path);
    } else {
        snprintf(url, len, "%s/ipfs/%s", storage->gateway, cid);
    }

    return url;
}

/* Stub implementations - TODO: Implement with multipart upload */

synor_error_t synor_storage_upload(synor_storage_t* storage,
    const uint8_t* data, size_t size,
    const synor_upload_options_t* options, synor_upload_response_t* result) {
    (void)storage; (void)data; (void)size; (void)options; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_upload_directory(synor_storage_t* storage,
    const synor_file_entry_t* files, size_t file_count,
    const char* dir_name, synor_upload_response_t* result) {
    (void)storage; (void)files; (void)file_count; (void)dir_name; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_download(synor_storage_t* storage,
    const char* cid, uint8_t** data, size_t* size) {
    (void)storage; (void)cid; (void)data; (void)size;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_download_stream(synor_storage_t* storage,
    const char* cid, synor_download_callback_t callback, void* user_data) {
    (void)storage; (void)cid; (void)callback; (void)user_data;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_pin(synor_storage_t* storage,
    const synor_pin_request_t* request, synor_pin_t* result) {
    (void)storage; (void)request; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_unpin(synor_storage_t* storage, const char* cid) {
    (void)storage; (void)cid;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_get_pin_status(synor_storage_t* storage,
    const char* cid, synor_pin_t* result) {
    (void)storage; (void)cid; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_list_pins(synor_storage_t* storage,
    synor_pin_status_t* status, int32_t limit, int32_t offset,
    synor_pin_list_t* result) {
    (void)storage; (void)status; (void)limit; (void)offset; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_create_car(synor_storage_t* storage,
    const synor_file_entry_t* entries, size_t entry_count,
    synor_car_file_t* result) {
    (void)storage; (void)entries; (void)entry_count; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_import_car(synor_storage_t* storage,
    const uint8_t* car_data, size_t car_size, synor_cid_list_t* result) {
    (void)storage; (void)car_data; (void)car_size; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_export_car(synor_storage_t* storage,
    const char* cid, uint8_t** data, size_t* size) {
    (void)storage; (void)cid; (void)data; (void)size;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_list_directory(synor_storage_t* storage,
    const char* cid, synor_directory_listing_t* result) {
    (void)storage; (void)cid; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_storage_get_stats(synor_storage_t* storage,
    synor_storage_stats_t* result) {
    (void)storage; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

/* Free functions */
void synor_upload_response_free(synor_upload_response_t* response) {
    if (!response) return;
    free(response->cid);
    free(response->name);
    free(response->created_at);
    memset(response, 0, sizeof(*response));
}

void synor_pin_free(synor_pin_t* pin) {
    if (!pin) return;
    free(pin->cid);
    free(pin->name);
    free(pin->created_at);
    free(pin->expires_at);
    for (size_t i = 0; i < pin->delegate_count; i++) {
        free(pin->delegates[i]);
    }
    free(pin->delegates);
    memset(pin, 0, sizeof(*pin));
}

void synor_pin_list_free(synor_pin_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_pin_free(&list->pins[i]);
    }
    free(list->pins);
    memset(list, 0, sizeof(*list));
}

void synor_car_file_free(synor_car_file_t* car) {
    if (!car) return;
    free(car->cid);
    for (size_t i = 0; i < car->root_count; i++) {
        free(car->roots[i]);
    }
    free(car->roots);
    free(car->created_at);
    memset(car, 0, sizeof(*car));
}

void synor_cid_list_free(synor_cid_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        free(list->cids[i]);
    }
    free(list->cids);
    memset(list, 0, sizeof(*list));
}

void synor_directory_entry_free(synor_directory_entry_t* entry) {
    if (!entry) return;
    free(entry->name);
    free(entry->cid);
    memset(entry, 0, sizeof(*entry));
}

void synor_directory_listing_free(synor_directory_listing_t* listing) {
    if (!listing) return;
    for (size_t i = 0; i < listing->count; i++) {
        synor_directory_entry_free(&listing->entries[i]);
    }
    free(listing->entries);
    memset(listing, 0, sizeof(*listing));
}
