/**
 * @file rpc.c
 * @brief Synor RPC SDK implementation
 */

#include <stdlib.h>
#include <string.h>
#include "synor/rpc.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 RPC structure */
struct synor_rpc {
    synor_http_client_t* http;
    synor_network_t network;
    char* ws_endpoint;
    /* WebSocket connection would go here */
};

/* Internal subscription structure */
struct synor_subscription {
    char* id;
    char* channel;
    void* callback;
    void* user_data;
    struct synor_rpc* rpc;
};

synor_rpc_t* synor_rpc_create(const synor_rpc_config_t* config) {
    if (!config || !config->api_key) {
        return NULL;
    }

    synor_rpc_t* rpc = calloc(1, sizeof(synor_rpc_t));
    if (!rpc) return NULL;

    const char* endpoint = config->endpoint ?
        config->endpoint : "https://rpc.synor.io/v1";
    const char* ws_endpoint = config->ws_endpoint ?
        config->ws_endpoint : "wss://rpc.synor.io/v1/ws";
    uint32_t timeout = config->timeout_ms > 0 ? config->timeout_ms : 30000;
    uint32_t retries = config->retries > 0 ? config->retries : 3;

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

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

    rpc->network = config->network;
    rpc->ws_endpoint = synor_strdup(ws_endpoint);

    return rpc;
}

void synor_rpc_destroy(synor_rpc_t* rpc) {
    if (!rpc) return;
    synor_http_client_destroy(rpc->http);
    free(rpc->ws_endpoint);
    free(rpc);
}

/* Stub implementations - TODO: Implement with JSON parsing */

synor_error_t synor_rpc_get_latest_block(synor_rpc_t* rpc, synor_block_t* result) {
    (void)rpc; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_rpc_get_block(synor_rpc_t* rpc, const char* hash_or_height,
    synor_block_t* result) {
    (void)rpc; (void)hash_or_height; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_rpc_get_block_header(synor_rpc_t* rpc, const char* hash_or_height,
    synor_block_header_t* result) {
    (void)rpc; (void)hash_or_height; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_rpc_get_transaction(synor_rpc_t* rpc, const char* txid,
    synor_rpc_transaction_t* result) {
    (void)rpc; (void)txid; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_rpc_get_raw_transaction(synor_rpc_t* rpc, const char* txid,
    char** hex) {
    (void)rpc; (void)txid; (void)hex;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_rpc_send_raw_transaction(synor_rpc_t* rpc, const char* hex,
    synor_submit_result_t* result) {
    (void)rpc; (void)hex; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_rpc_decode_raw_transaction(synor_rpc_t* rpc, const char* hex,
    synor_rpc_transaction_t* result) {
    (void)rpc; (void)hex; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_rpc_estimate_fee(synor_rpc_t* rpc, synor_priority_t priority,
    synor_fee_estimate_t* result) {
    (void)rpc; (void)priority; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_rpc_get_chain_info(synor_rpc_t* rpc, synor_chain_info_t* result) {
    (void)rpc; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_rpc_get_mempool_info(synor_rpc_t* rpc, synor_mempool_info_t* result) {
    (void)rpc; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_subscription_t* synor_rpc_subscribe_blocks(synor_rpc_t* rpc,
    synor_block_callback_t callback, void* user_data) {
    (void)rpc; (void)callback; (void)user_data;
    return NULL; /* TODO: Implement WebSocket */
}

synor_subscription_t* synor_rpc_subscribe_address(synor_rpc_t* rpc,
    const char* address, synor_tx_callback_t callback, void* user_data) {
    (void)rpc; (void)address; (void)callback; (void)user_data;
    return NULL;
}

synor_subscription_t* synor_rpc_subscribe_mempool(synor_rpc_t* rpc,
    synor_tx_callback_t callback, void* user_data) {
    (void)rpc; (void)callback; (void)user_data;
    return NULL;
}

void synor_subscription_cancel(synor_subscription_t* sub) {
    if (!sub) return;
    free(sub->id);
    free(sub->channel);
    free(sub);
}

/* Free functions */
void synor_block_header_free(synor_block_header_t* header) {
    if (!header) return;
    free(header->hash);
    free(header->previous_hash);
    free(header->merkle_root);
    memset(header, 0, sizeof(*header));
}

void synor_block_free(synor_block_t* block) {
    if (!block) return;
    free(block->hash);
    free(block->previous_hash);
    free(block->merkle_root);
    for (size_t i = 0; i < block->transaction_count; i++) {
        synor_rpc_transaction_free(&block->transactions[i]);
    }
    free(block->transactions);
    memset(block, 0, sizeof(*block));
}

void synor_rpc_transaction_free(synor_rpc_transaction_t* tx) {
    if (!tx) return;
    free(tx->txid);
    free(tx->hash);
    free(tx->block_hash);
    for (size_t i = 0; i < tx->input_count; i++) {
        free(tx->inputs[i].txid);
        free(tx->inputs[i].script_sig);
        for (size_t j = 0; j < tx->inputs[i].witness_count; j++) {
            free(tx->inputs[i].witness[j]);
        }
        free(tx->inputs[i].witness);
    }
    free(tx->inputs);
    for (size_t i = 0; i < tx->output_count; i++) {
        free(tx->outputs[i].script_pubkey.asm_str);
        free(tx->outputs[i].script_pubkey.hex);
        free(tx->outputs[i].script_pubkey.type);
        free(tx->outputs[i].script_pubkey.address);
    }
    free(tx->outputs);
    memset(tx, 0, sizeof(*tx));
}

void synor_chain_info_free(synor_chain_info_t* info) {
    if (!info) return;
    free(info->chain);
    free(info->best_block_hash);
    free(info->chain_work);
    memset(info, 0, sizeof(*info));
}

void synor_mempool_info_free(synor_mempool_info_t* info) {
    (void)info; /* No dynamic members */
}

void synor_submit_result_free(synor_submit_result_t* result) {
    if (!result) return;
    free(result->txid);
    free(result->reason);
    memset(result, 0, sizeof(*result));
}
