/**
 * @file economics.c
 * @brief Synor Economics SDK implementation
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "synor/economics.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);
int synor_http_get(synor_http_client_t* client, const char* path,
    char** response, size_t* response_size);
int 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);
char* synor_url_encode(const char* s);

/* Internal economics structure */
struct synor_economics {
    synor_http_client_t* http;
    bool closed;
    bool debug;
};

static const char* service_type_to_string(synor_service_type_t type) {
    switch (type) {
        case SYNOR_SERVICE_COMPUTE: return "compute";
        case SYNOR_SERVICE_STORAGE: return "storage";
        case SYNOR_SERVICE_DATABASE: return "database";
        case SYNOR_SERVICE_HOSTING: return "hosting";
        case SYNOR_SERVICE_RPC: return "rpc";
        case SYNOR_SERVICE_BRIDGE: return "bridge";
        default: return "unknown";
    }
}

static const char* billing_period_to_string(synor_billing_period_t period) {
    switch (period) {
        case SYNOR_BILLING_HOURLY: return "hourly";
        case SYNOR_BILLING_DAILY: return "daily";
        case SYNOR_BILLING_WEEKLY: return "weekly";
        case SYNOR_BILLING_MONTHLY: return "monthly";
        default: return "monthly";
    }
}

synor_economics_t* synor_economics_create(const synor_economics_config_t* config) {
    if (!config || !config->api_key) {
        return NULL;
    }

    synor_economics_t* economics = calloc(1, sizeof(synor_economics_t));
    if (!economics) return NULL;

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

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

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

    economics->closed = false;
    economics->debug = config->debug;
    return economics;
}

void synor_economics_destroy(synor_economics_t* economics) {
    if (!economics) return;
    economics->closed = true;
    synor_http_client_destroy(economics->http);
    free(economics);
}

bool synor_economics_is_closed(synor_economics_t* economics) {
    return economics ? economics->closed : true;
}

bool synor_economics_health_check(synor_economics_t* economics) {
    if (!economics || economics->closed) return false;

    char* response = NULL;
    size_t response_size = 0;

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

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

/* ==================== Pricing Operations ==================== */

synor_economics_error_t synor_economics_get_pricing(synor_economics_t* economics,
    synor_service_type_t* service, synor_service_pricing_list_t* result) {
    if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;
    (void)service; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_get_price(synor_economics_t* economics,
    synor_service_type_t service, const synor_usage_metrics_t* usage,
    synor_price_result_t* result) {
    if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;
    if (!usage || !result) return SYNOR_ECONOMICS_ERROR_UNKNOWN;

    char body[1024];
    snprintf(body, sizeof(body),
        "{\"service\":\"%s\",\"computeUnits\":%.2f,\"storageBytes\":%.2f,\"bandwidthBytes\":%.2f,\"durationSeconds\":%lld,\"requests\":%d}",
        service_type_to_string(service),
        usage->compute_units, usage->storage_bytes, usage->bandwidth_bytes,
        (long long)usage->duration_seconds, usage->requests);

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_post(economics->http, "/pricing/calculate", body, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_ECONOMICS_ERROR_HTTP;
    }

    /* TODO: Parse JSON response */
    free(response);
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_estimate_cost(synor_economics_t* economics,
    const synor_usage_plan_t* plan, synor_cost_estimate_t* result) {
    (void)economics; (void)plan; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

void synor_service_pricing_free(synor_service_pricing_t* pricing) {
    if (!pricing) return;
    free(pricing->unit);
    free(pricing->price_per_unit);
    free(pricing->currency);
}

void synor_service_pricing_list_free(synor_service_pricing_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_service_pricing_free(&list->prices[i]);
    }
    free(list->prices);
    list->prices = NULL;
    list->count = 0;
}

void synor_price_result_free(synor_price_result_t* result) {
    if (!result) return;
    free(result->amount);
    free(result->currency);
}

void synor_cost_estimate_free(synor_cost_estimate_t* estimate) {
    if (!estimate) return;
    free(estimate->total);
    free(estimate->currency);
    for (size_t i = 0; i < estimate->breakdown_count; i++) {
        free(estimate->breakdown[i].amount);
    }
    free(estimate->breakdown);
    free(estimate->discount_applied);
}

/* ==================== Billing Operations ==================== */

synor_economics_error_t synor_economics_get_usage(synor_economics_t* economics,
    synor_billing_period_t* period, synor_usage_t* result) {
    if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;

    char path[256];
    if (period) {
        snprintf(path, sizeof(path), "/billing/usage?period=%s", billing_period_to_string(*period));
    } else {
        snprintf(path, sizeof(path), "/billing/usage");
    }

    char* response = NULL;
    size_t response_size = 0;

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

    /* TODO: Parse JSON response */
    (void)result;
    free(response);
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_get_invoices(synor_economics_t* economics,
    synor_invoice_list_t* result) {
    (void)economics; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_get_invoice(synor_economics_t* economics,
    const char* invoice_id, synor_invoice_t* result) {
    (void)economics; (void)invoice_id; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_get_balance(synor_economics_t* economics,
    synor_account_balance_t* result) {
    (void)economics; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

void synor_usage_free(synor_usage_t* usage) {
    if (!usage) return;
    for (size_t i = 0; i < usage->items_count; i++) {
        free(usage->items[i].cost);
    }
    free(usage->items);
    free(usage->total_cost);
    free(usage->currency);
}

void synor_invoice_free(synor_invoice_t* invoice) {
    if (!invoice) return;
    free(invoice->id);
    for (size_t i = 0; i < invoice->lines_count; i++) {
        free(invoice->lines[i].service);
        free(invoice->lines[i].description);
        free(invoice->lines[i].unit_price);
        free(invoice->lines[i].amount);
    }
    free(invoice->lines);
    free(invoice->subtotal);
    free(invoice->discount);
    free(invoice->tax);
    free(invoice->total);
    free(invoice->currency);
    free(invoice->pdf_url);
}

void synor_invoice_list_free(synor_invoice_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_invoice_free(&list->invoices[i]);
    }
    free(list->invoices);
    list->invoices = NULL;
    list->count = 0;
}

void synor_account_balance_free(synor_account_balance_t* balance) {
    if (!balance) return;
    free(balance->available);
    free(balance->pending);
    free(balance->staked);
    free(balance->total);
    free(balance->currency);
}

/* ==================== Staking Operations ==================== */

synor_economics_error_t synor_economics_stake(synor_economics_t* economics,
    const char* amount, int32_t duration_days, synor_stake_receipt_t* result) {
    if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;
    if (!amount || !result) return SYNOR_ECONOMICS_ERROR_UNKNOWN;

    char body[256];
    snprintf(body, sizeof(body), "{\"amount\":\"%s\",\"durationDays\":%d}", amount, duration_days);

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_post(economics->http, "/staking/stake", body, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_ECONOMICS_ERROR_HTTP;
    }

    /* TODO: Parse JSON response */
    free(response);
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_unstake(synor_economics_t* economics,
    const char* stake_id, synor_unstake_receipt_t* result) {
    (void)economics; (void)stake_id; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_get_stakes(synor_economics_t* economics,
    synor_stake_list_t* result) {
    (void)economics; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_get_stake(synor_economics_t* economics,
    const char* stake_id, synor_stake_t* result) {
    (void)economics; (void)stake_id; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_get_staking_rewards(synor_economics_t* economics,
    synor_staking_rewards_t* result) {
    (void)economics; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_claim_rewards(synor_economics_t* economics,
    synor_stake_receipt_t* result) {
    (void)economics; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

void synor_stake_free(synor_stake_t* stake) {
    if (!stake) return;
    free(stake->id);
    free(stake->amount);
    free(stake->rewards_earned);
}

void synor_stake_list_free(synor_stake_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_stake_free(&list->stakes[i]);
    }
    free(list->stakes);
    list->stakes = NULL;
    list->count = 0;
}

void synor_stake_receipt_free(synor_stake_receipt_t* receipt) {
    if (!receipt) return;
    free(receipt->id);
    free(receipt->amount);
    free(receipt->tx_hash);
}

void synor_unstake_receipt_free(synor_unstake_receipt_t* receipt) {
    if (!receipt) return;
    free(receipt->id);
    free(receipt->amount);
    free(receipt->tx_hash);
}

void synor_staking_rewards_free(synor_staking_rewards_t* rewards) {
    if (!rewards) return;
    free(rewards->pending);
    free(rewards->claimed);
    free(rewards->total);
}

/* ==================== Discount Operations ==================== */

synor_economics_error_t synor_economics_apply_discount(synor_economics_t* economics,
    const char* code, synor_discount_result_t* result) {
    if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;
    if (!code || !result) return SYNOR_ECONOMICS_ERROR_UNKNOWN;

    char body[256];
    snprintf(body, sizeof(body), "{\"code\":\"%s\"}", code);

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_post(economics->http, "/discounts/apply", body, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_ECONOMICS_ERROR_HTTP;
    }

    /* TODO: Parse JSON response */
    free(response);
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_remove_discount(synor_economics_t* economics,
    const char* code) {
    (void)economics; (void)code;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

synor_economics_error_t synor_economics_get_discounts(synor_economics_t* economics,
    synor_discount_list_t* result) {
    (void)economics; (void)result;
    return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}

void synor_discount_free(synor_discount_t* discount) {
    if (!discount) return;
    free(discount->code);
    free(discount->value);
    free(discount->description);
    free(discount->applicable_services);
}

void synor_discount_list_free(synor_discount_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_discount_free(&list->discounts[i]);
    }
    free(list->discounts);
    list->discounts = NULL;
    list->count = 0;
}

void synor_discount_result_free(synor_discount_result_t* result) {
    if (!result) return;
    synor_discount_free(&result->discount);
    free(result->savings_estimate);
}
