/**
 * @file wallet.c
 * @brief Synor Wallet SDK implementation
 */

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

#ifdef HAVE_JANSSON
#include <jansson.h>
#endif

/* 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 wallet structure */
struct synor_wallet {
    synor_http_client_t* http;
    synor_network_t network;
};

synor_wallet_t* synor_wallet_create(const synor_wallet_config_t* config) {
    if (!config || !config->api_key) {
        return NULL;
    }

    synor_wallet_t* wallet = calloc(1, sizeof(synor_wallet_t));
    if (!wallet) return NULL;

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

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

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

    wallet->network = config->network;
    return wallet;
}

void synor_wallet_destroy(synor_wallet_t* wallet) {
    if (!wallet) return;
    synor_http_client_destroy(wallet->http);
    free(wallet);
}

#ifdef HAVE_JANSSON

static synor_error_t parse_wallet_info(json_t* json, synor_wallet_info_t* info) {
    if (!json || !info) return SYNOR_ERROR_INVALID_ARGUMENT;

    memset(info, 0, sizeof(*info));

    json_t* id = json_object_get(json, "id");
    if (id) info->id = synor_strdup(json_string_value(id));

    json_t* type = json_object_get(json, "type");
    if (type) {
        const char* type_str = json_string_value(type);
        if (strcmp(type_str, "standard") == 0) info->type = SYNOR_WALLET_STANDARD;
        else if (strcmp(type_str, "multisig") == 0) info->type = SYNOR_WALLET_MULTISIG;
        else if (strcmp(type_str, "hardware") == 0) info->type = SYNOR_WALLET_HARDWARE;
        else if (strcmp(type_str, "stealth") == 0) info->type = SYNOR_WALLET_STEALTH;
    }

    json_t* network = json_object_get(json, "network");
    if (network) {
        const char* net_str = json_string_value(network);
        if (strcmp(net_str, "mainnet") == 0) info->network = SYNOR_NETWORK_MAINNET;
        else if (strcmp(net_str, "testnet") == 0) info->network = SYNOR_NETWORK_TESTNET;
        else if (strcmp(net_str, "devnet") == 0) info->network = SYNOR_NETWORK_DEVNET;
    }

    json_t* created_at = json_object_get(json, "created_at");
    if (created_at) info->created_at = synor_strdup(json_string_value(created_at));

    json_t* addresses = json_object_get(json, "addresses");
    if (addresses && json_is_array(addresses)) {
        size_t count = json_array_size(addresses);
        info->addresses = calloc(count, sizeof(synor_address_t));
        info->address_count = count;

        for (size_t i = 0; i < count; i++) {
            json_t* addr = json_array_get(addresses, i);
            info->addresses[i].address = synor_strdup(
                json_string_value(json_object_get(addr, "address")));
            info->addresses[i].index = (int32_t)json_integer_value(
                json_object_get(addr, "index"));
            info->addresses[i].is_change = json_boolean_value(
                json_object_get(addr, "is_change"));
        }
    }

    return SYNOR_OK;
}

synor_error_t synor_wallet_create_wallet(
    synor_wallet_t* wallet,
    synor_wallet_type_t type,
    synor_create_wallet_result_t* result
) {
    if (!wallet || !result) return SYNOR_ERROR_INVALID_ARGUMENT;

    const char* type_str;
    switch (type) {
        case SYNOR_WALLET_STANDARD: type_str = "standard"; break;
        case SYNOR_WALLET_MULTISIG: type_str = "multisig"; break;
        case SYNOR_WALLET_HARDWARE: type_str = "hardware"; break;
        case SYNOR_WALLET_STEALTH: type_str = "stealth"; break;
        default: return SYNOR_ERROR_INVALID_ARGUMENT;
    }

    const char* net_str;
    switch (wallet->network) {
        case SYNOR_NETWORK_MAINNET: net_str = "mainnet"; break;
        case SYNOR_NETWORK_TESTNET: net_str = "testnet"; break;
        case SYNOR_NETWORK_DEVNET: net_str = "devnet"; break;
        default: net_str = "mainnet"; break;
    }

    char body[256];
    snprintf(body, sizeof(body),
        "{\"type\":\"%s\",\"network\":\"%s\"}", type_str, net_str);

    char* response = NULL;
    synor_error_t err = synor_http_post(wallet->http, "/wallets", body,
        &response, NULL);

    if (err != SYNOR_OK) return err;

    json_error_t json_err;
    json_t* json = json_loads(response, 0, &json_err);
    free(response);

    if (!json) return SYNOR_ERROR_JSON_PARSE;

    memset(result, 0, sizeof(*result));

    json_t* wallet_json = json_object_get(json, "wallet");
    if (wallet_json) {
        parse_wallet_info(wallet_json, &result->wallet);
    }

    json_t* mnemonic = json_object_get(json, "mnemonic");
    if (mnemonic) {
        result->mnemonic = synor_strdup(json_string_value(mnemonic));
    }

    json_decref(json);
    return SYNOR_OK;
}

synor_error_t synor_wallet_get_balance(
    synor_wallet_t* wallet,
    const char* address,
    synor_balance_t* result
) {
    if (!wallet || !address || !result) return SYNOR_ERROR_INVALID_ARGUMENT;

    char path[512];
    snprintf(path, sizeof(path), "/addresses/%s/balance", address);

    char* response = NULL;
    synor_error_t err = synor_http_get(wallet->http, path, &response, NULL);

    if (err != SYNOR_OK) return err;

    json_error_t json_err;
    json_t* json = json_loads(response, 0, &json_err);
    free(response);

    if (!json) return SYNOR_ERROR_JSON_PARSE;

    result->confirmed = json_integer_value(json_object_get(json, "confirmed"));
    result->unconfirmed = json_integer_value(json_object_get(json, "unconfirmed"));
    result->total = json_integer_value(json_object_get(json, "total"));

    json_decref(json);
    return SYNOR_OK;
}

#else /* No JANSSON */

synor_error_t synor_wallet_create_wallet(
    synor_wallet_t* wallet,
    synor_wallet_type_t type,
    synor_create_wallet_result_t* result
) {
    (void)wallet; (void)type; (void)result;
    return SYNOR_ERROR_UNKNOWN; /* JSON parsing not available */
}

synor_error_t synor_wallet_get_balance(
    synor_wallet_t* wallet,
    const char* address,
    synor_balance_t* result
) {
    (void)wallet; (void)address; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

#endif /* HAVE_JANSSON */

/* Stub implementations for remaining functions */
synor_error_t synor_wallet_import(
    synor_wallet_t* wallet, const char* mnemonic,
    const char* passphrase, synor_wallet_info_t* result
) {
    (void)wallet; (void)mnemonic; (void)passphrase; (void)result;
    return SYNOR_ERROR_UNKNOWN; /* TODO: Implement */
}

synor_error_t synor_wallet_get(
    synor_wallet_t* wallet, const char* wallet_id,
    synor_wallet_info_t* result
) {
    (void)wallet; (void)wallet_id; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_wallet_generate_address(
    synor_wallet_t* wallet, const char* wallet_id,
    bool is_change, synor_address_t* result
) {
    (void)wallet; (void)wallet_id; (void)is_change; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_wallet_get_stealth_address(
    synor_wallet_t* wallet, const char* wallet_id,
    synor_stealth_address_t* result
) {
    (void)wallet; (void)wallet_id; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_wallet_sign_transaction(
    synor_wallet_t* wallet, const char* wallet_id,
    const synor_transaction_t* transaction, synor_signed_tx_t* result
) {
    (void)wallet; (void)wallet_id; (void)transaction; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_wallet_sign_message(
    synor_wallet_t* wallet, const char* wallet_id,
    const char* message, int32_t address_index, synor_signature_t* result
) {
    (void)wallet; (void)wallet_id; (void)message; (void)address_index; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_wallet_verify_message(
    synor_wallet_t* wallet, const char* message,
    const char* signature, const char* address, bool* is_valid
) {
    (void)wallet; (void)message; (void)signature; (void)address; (void)is_valid;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_wallet_get_utxos(
    synor_wallet_t* wallet, const char* address,
    int32_t min_confirmations, synor_utxo_list_t* result
) {
    (void)wallet; (void)address; (void)min_confirmations; (void)result;
    return SYNOR_ERROR_UNKNOWN;
}

synor_error_t synor_wallet_estimate_fee(
    synor_wallet_t* wallet, synor_priority_t priority, int64_t* fee_per_byte
) {
    (void)wallet; (void)priority; (void)fee_per_byte;
    return SYNOR_ERROR_UNKNOWN;
}

/* Free functions */
void synor_address_free(synor_address_t* addr) {
    if (!addr) return;
    free(addr->address);
    memset(addr, 0, sizeof(*addr));
}

void synor_wallet_info_free(synor_wallet_info_t* info) {
    if (!info) return;
    free(info->id);
    free(info->created_at);
    for (size_t i = 0; i < info->address_count; i++) {
        synor_address_free(&info->addresses[i]);
    }
    free(info->addresses);
    memset(info, 0, sizeof(*info));
}

void synor_stealth_address_free(synor_stealth_address_t* addr) {
    if (!addr) return;
    free(addr->spend_public_key);
    free(addr->view_public_key);
    free(addr->one_time_address);
    memset(addr, 0, sizeof(*addr));
}

void synor_create_wallet_result_free(synor_create_wallet_result_t* result) {
    if (!result) return;
    synor_wallet_info_free(&result->wallet);
    free(result->mnemonic);
    memset(result, 0, sizeof(*result));
}

void synor_signed_tx_free(synor_signed_tx_t* tx) {
    if (!tx) return;
    free(tx->txid);
    free(tx->hex);
    memset(tx, 0, sizeof(*tx));
}

void synor_signature_free(synor_signature_t* sig) {
    if (!sig) return;
    free(sig->signature);
    free(sig->address);
    memset(sig, 0, sizeof(*sig));
}

void synor_utxo_free(synor_utxo_t* utxo) {
    if (!utxo) return;
    free(utxo->txid);
    free(utxo->address);
    free(utxo->script_pubkey);
    memset(utxo, 0, sizeof(*utxo));
}

void synor_utxo_list_free(synor_utxo_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_utxo_free(&list->utxos[i]);
    }
    free(list->utxos);
    memset(list, 0, sizeof(*list));
}
