/**
 * @file governance.c
 * @brief Synor Governance SDK implementation
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "synor/governance.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 governance structure */
struct synor_governance {
    synor_http_client_t* http;
    bool closed;
    bool debug;
};

static const synor_proposal_status_t FINAL_STATUSES[] = {
    SYNOR_PROPOSAL_PASSED,
    SYNOR_PROPOSAL_REJECTED,
    SYNOR_PROPOSAL_EXECUTED,
    SYNOR_PROPOSAL_CANCELLED
};
static const size_t FINAL_STATUSES_COUNT = sizeof(FINAL_STATUSES) / sizeof(FINAL_STATUSES[0]);

static bool is_final_status(synor_proposal_status_t status) {
    for (size_t i = 0; i < FINAL_STATUSES_COUNT; i++) {
        if (FINAL_STATUSES[i] == status) return true;
    }
    return false;
}

static const char* vote_choice_to_string(synor_vote_choice_t choice) {
    switch (choice) {
        case SYNOR_VOTE_FOR: return "for";
        case SYNOR_VOTE_AGAINST: return "against";
        case SYNOR_VOTE_ABSTAIN: return "abstain";
        default: return "abstain";
    }
}

static const char* dao_type_to_string(synor_dao_type_t type) {
    switch (type) {
        case SYNOR_DAO_TOKEN: return "token";
        case SYNOR_DAO_MULTISIG: return "multisig";
        case SYNOR_DAO_HYBRID: return "hybrid";
        default: return "token";
    }
}

synor_governance_t* synor_governance_create(const synor_governance_config_t* config) {
    if (!config || !config->api_key) {
        return NULL;
    }

    synor_governance_t* governance = calloc(1, sizeof(synor_governance_t));
    if (!governance) return NULL;

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

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

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

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

void synor_governance_destroy(synor_governance_t* governance) {
    if (!governance) return;
    governance->closed = true;
    synor_http_client_destroy(governance->http);
    free(governance);
}

bool synor_governance_is_closed(synor_governance_t* governance) {
    return governance ? governance->closed : true;
}

bool synor_governance_health_check(synor_governance_t* governance) {
    if (!governance || governance->closed) return false;

    char* response = NULL;
    size_t response_size = 0;

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

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

/* ==================== Proposal Operations ==================== */

synor_governance_error_t synor_governance_create_proposal(synor_governance_t* governance,
    const synor_proposal_draft_t* draft, synor_proposal_t* result) {
    if (!governance || governance->closed) return SYNOR_GOVERNANCE_ERROR_CLIENT_CLOSED;
    if (!draft || !result) return SYNOR_GOVERNANCE_ERROR_UNKNOWN;

    char body[4096];
    snprintf(body, sizeof(body),
        "{\"title\":\"%s\",\"description\":\"%s\"}",
        draft->title, draft->description);

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_post(governance->http, "/proposals", body, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_GOVERNANCE_ERROR_HTTP;
    }

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

synor_governance_error_t synor_governance_get_proposal(synor_governance_t* governance,
    const char* proposal_id, synor_proposal_t* result) {
    (void)governance; (void)proposal_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_list_proposals(synor_governance_t* governance,
    const synor_proposal_filter_t* filter, synor_proposal_list_t* result) {
    (void)governance; (void)filter; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_cancel_proposal(synor_governance_t* governance,
    const char* proposal_id, synor_proposal_t* result) {
    (void)governance; (void)proposal_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_execute_proposal(synor_governance_t* governance,
    const char* proposal_id, synor_proposal_t* result) {
    (void)governance; (void)proposal_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_wait_for_proposal(synor_governance_t* governance,
    const char* proposal_id, uint32_t poll_interval_ms, uint32_t max_wait_ms,
    synor_proposal_t* result) {
    (void)governance; (void)proposal_id; (void)poll_interval_ms;
    (void)max_wait_ms; (void)result;
    (void)is_final_status;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

void synor_proposal_free(synor_proposal_t* proposal) {
    if (!proposal) return;
    free(proposal->id);
    free(proposal->title);
    free(proposal->description);
    free(proposal->discussion_url);
    free(proposal->proposer);
    free(proposal->vote_tally.for_votes);
    free(proposal->vote_tally.against_votes);
    free(proposal->vote_tally.abstain_votes);
    free(proposal->vote_tally.quorum);
    free(proposal->vote_tally.quorum_required);
    for (size_t i = 0; i < proposal->actions_count; i++) {
        free(proposal->actions[i].target);
        free(proposal->actions[i].method);
        free(proposal->actions[i].data);
        free(proposal->actions[i].value);
    }
    free(proposal->actions);
    free(proposal->dao_id);
}

void synor_proposal_list_free(synor_proposal_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_proposal_free(&list->proposals[i]);
    }
    free(list->proposals);
    list->proposals = NULL;
    list->count = 0;
}

/* ==================== Voting Operations ==================== */

synor_governance_error_t synor_governance_vote(synor_governance_t* governance,
    const char* proposal_id, const synor_vote_t* vote, const char* weight,
    synor_vote_receipt_t* result) {
    if (!governance || governance->closed) return SYNOR_GOVERNANCE_ERROR_CLIENT_CLOSED;
    if (!proposal_id || !vote || !result) return SYNOR_GOVERNANCE_ERROR_UNKNOWN;

    char body[512];
    if (vote->reason && weight) {
        snprintf(body, sizeof(body),
            "{\"choice\":\"%s\",\"reason\":\"%s\",\"weight\":\"%s\"}",
            vote_choice_to_string(vote->choice), vote->reason, weight);
    } else if (vote->reason) {
        snprintf(body, sizeof(body),
            "{\"choice\":\"%s\",\"reason\":\"%s\"}",
            vote_choice_to_string(vote->choice), vote->reason);
    } else if (weight) {
        snprintf(body, sizeof(body),
            "{\"choice\":\"%s\",\"weight\":\"%s\"}",
            vote_choice_to_string(vote->choice), weight);
    } else {
        snprintf(body, sizeof(body), "{\"choice\":\"%s\"}", vote_choice_to_string(vote->choice));
    }

    char path[256];
    snprintf(path, sizeof(path), "/proposals/%s/vote", proposal_id);

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_post(governance->http, path, body, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_GOVERNANCE_ERROR_HTTP;
    }

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

synor_governance_error_t synor_governance_get_votes(synor_governance_t* governance,
    const char* proposal_id, synor_vote_receipt_list_t* result) {
    (void)governance; (void)proposal_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_get_my_vote(synor_governance_t* governance,
    const char* proposal_id, synor_vote_receipt_t* result) {
    (void)governance; (void)proposal_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_delegate(synor_governance_t* governance,
    const char* delegatee, const char* amount, synor_delegation_receipt_t* result) {
    if (!governance || governance->closed) return SYNOR_GOVERNANCE_ERROR_CLIENT_CLOSED;
    if (!delegatee || !result) return SYNOR_GOVERNANCE_ERROR_UNKNOWN;

    char body[256];
    if (amount) {
        snprintf(body, sizeof(body), "{\"delegatee\":\"%s\",\"amount\":\"%s\"}", delegatee, amount);
    } else {
        snprintf(body, sizeof(body), "{\"delegatee\":\"%s\"}", delegatee);
    }

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_post(governance->http, "/voting/delegate", body, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_GOVERNANCE_ERROR_HTTP;
    }

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

synor_governance_error_t synor_governance_undelegate(synor_governance_t* governance,
    const char* delegatee, synor_delegation_receipt_t* result) {
    (void)governance; (void)delegatee; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_get_voting_power(synor_governance_t* governance,
    const char* address, synor_voting_power_t* result) {
    (void)governance; (void)address; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_get_delegations(synor_governance_t* governance,
    const char* address, synor_delegation_receipt_list_t* result) {
    (void)governance; (void)address; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

void synor_vote_receipt_free(synor_vote_receipt_t* receipt) {
    if (!receipt) return;
    free(receipt->id);
    free(receipt->proposal_id);
    free(receipt->voter);
    free(receipt->weight);
    free(receipt->reason);
    free(receipt->tx_hash);
}

void synor_vote_receipt_list_free(synor_vote_receipt_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_vote_receipt_free(&list->votes[i]);
    }
    free(list->votes);
    list->votes = NULL;
    list->count = 0;
}

void synor_voting_power_free(synor_voting_power_t* power) {
    if (!power) return;
    free(power->address);
    free(power->delegated_power);
    free(power->own_power);
    free(power->total_power);
    for (size_t i = 0; i < power->delegators_count; i++) {
        free(power->delegators[i]);
    }
    free(power->delegators);
}

void synor_delegation_receipt_free(synor_delegation_receipt_t* receipt) {
    if (!receipt) return;
    free(receipt->id);
    free(receipt->from);
    free(receipt->to);
    free(receipt->amount);
    free(receipt->tx_hash);
}

void synor_delegation_receipt_list_free(synor_delegation_receipt_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_delegation_receipt_free(&list->delegations[i]);
    }
    free(list->delegations);
    list->delegations = NULL;
    list->count = 0;
}

/* ==================== DAO Operations ==================== */

synor_governance_error_t synor_governance_create_dao(synor_governance_t* governance,
    const synor_dao_config_t* config, synor_dao_t* result) {
    if (!governance || governance->closed) return SYNOR_GOVERNANCE_ERROR_CLIENT_CLOSED;
    if (!config || !result) return SYNOR_GOVERNANCE_ERROR_UNKNOWN;

    char body[2048];
    snprintf(body, sizeof(body),
        "{\"name\":\"%s\",\"description\":\"%s\",\"type\":\"%s\",\"votingPeriodDays\":%d,\"timelockDays\":%d}",
        config->name, config->description, dao_type_to_string(config->type),
        config->voting_period_days, config->timelock_days);

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_post(governance->http, "/daos", body, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_GOVERNANCE_ERROR_HTTP;
    }

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

synor_governance_error_t synor_governance_get_dao(synor_governance_t* governance,
    const char* dao_id, synor_dao_t* result) {
    (void)governance; (void)dao_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_list_daos(synor_governance_t* governance,
    int32_t limit, int32_t offset, synor_dao_list_t* result) {
    (void)governance; (void)limit; (void)offset; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_get_dao_treasury(synor_governance_t* governance,
    const char* dao_id, synor_dao_treasury_t* result) {
    (void)governance; (void)dao_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_get_dao_members(synor_governance_t* governance,
    const char* dao_id, char*** members, size_t* count) {
    (void)governance; (void)dao_id; (void)members; (void)count;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

void synor_dao_free(synor_dao_t* dao) {
    if (!dao) return;
    free(dao->id);
    free(dao->name);
    free(dao->description);
    free(dao->token_address);
    free(dao->proposal_threshold);
    free(dao->treasury_value);
}

void synor_dao_list_free(synor_dao_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_dao_free(&list->daos[i]);
    }
    free(list->daos);
    list->daos = NULL;
    list->count = 0;
}

void synor_dao_treasury_free(synor_dao_treasury_t* treasury) {
    if (!treasury) return;
    free(treasury->dao_id);
    free(treasury->total_value);
    for (size_t i = 0; i < treasury->tokens_count; i++) {
        free(treasury->tokens[i].address);
        free(treasury->tokens[i].balance);
        free(treasury->tokens[i].name);
        free(treasury->tokens[i].symbol);
    }
    free(treasury->tokens);
}

/* ==================== Vesting Operations ==================== */

synor_governance_error_t synor_governance_create_vesting(synor_governance_t* governance,
    const synor_vesting_schedule_t* schedule, synor_vesting_contract_t* result) {
    if (!governance || governance->closed) return SYNOR_GOVERNANCE_ERROR_CLIENT_CLOSED;
    if (!schedule || !result) return SYNOR_GOVERNANCE_ERROR_UNKNOWN;

    char body[1024];
    snprintf(body, sizeof(body),
        "{\"beneficiary\":\"%s\",\"totalAmount\":\"%s\",\"startTime\":%lld,\"cliffDuration\":%lld,\"vestingDuration\":%lld,\"revocable\":%s}",
        schedule->beneficiary, schedule->total_amount,
        (long long)schedule->start_time, (long long)schedule->cliff_duration,
        (long long)schedule->vesting_duration, schedule->revocable ? "true" : "false");

    char* response = NULL;
    size_t response_size = 0;

    int err = synor_http_post(governance->http, "/vesting", body, &response, &response_size);
    if (err != 0) {
        free(response);
        return SYNOR_GOVERNANCE_ERROR_HTTP;
    }

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

synor_governance_error_t synor_governance_get_vesting(synor_governance_t* governance,
    const char* contract_id, synor_vesting_contract_t* result) {
    (void)governance; (void)contract_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_list_vesting(synor_governance_t* governance,
    const char* beneficiary, synor_vesting_contract_list_t* result) {
    (void)governance; (void)beneficiary; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_claim_vested(synor_governance_t* governance,
    const char* contract_id, synor_claim_receipt_t* result) {
    (void)governance; (void)contract_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_revoke_vesting(synor_governance_t* governance,
    const char* contract_id, synor_vesting_contract_t* result) {
    (void)governance; (void)contract_id; (void)result;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

synor_governance_error_t synor_governance_get_releasable(synor_governance_t* governance,
    const char* contract_id, char** amount) {
    (void)governance; (void)contract_id; (void)amount;
    return SYNOR_GOVERNANCE_ERROR_UNKNOWN;
}

void synor_vesting_contract_free(synor_vesting_contract_t* contract) {
    if (!contract) return;
    free(contract->id);
    free(contract->beneficiary);
    free(contract->grantor);
    free(contract->total_amount);
    free(contract->released_amount);
    free(contract->releasable_amount);
}

void synor_vesting_contract_list_free(synor_vesting_contract_list_t* list) {
    if (!list) return;
    for (size_t i = 0; i < list->count; i++) {
        synor_vesting_contract_free(&list->contracts[i]);
    }
    free(list->contracts);
    list->contracts = NULL;
    list->count = 0;
}

void synor_claim_receipt_free(synor_claim_receipt_t* receipt) {
    if (!receipt) return;
    free(receipt->id);
    free(receipt->contract_id);
    free(receipt->amount);
    free(receipt->tx_hash);
}
