/**
 * Synor Compiler SDK Examples for C
 *
 * Demonstrates smart contract compilation and analysis:
 * - WASM contract compilation and optimization
 * - ABI extraction and encoding
 * - Contract analysis and security scanning
 * - Validation and verification
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <synor/compiler.h>

// Helper function to create a minimal valid WASM module for testing
void create_minimal_wasm(uint8_t** wasm, size_t* wasm_len) {
    static const uint8_t minimal_wasm[] = {
        0x00, 0x61, 0x73, 0x6d, // Magic: \0asm
        0x01, 0x00, 0x00, 0x00, // Version: 1
        // Type section
        0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f,
        // Function section
        0x03, 0x02, 0x01, 0x00,
        // Export section
        0x07, 0x08, 0x01, 0x04, 0x61, 0x64, 0x64, 0x00, 0x00,
        // Code section
        0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
    };

    *wasm_len = sizeof(minimal_wasm);
    *wasm = (uint8_t*)malloc(*wasm_len);
    memcpy(*wasm, minimal_wasm, *wasm_len);
}

void compile_contract_example(synor_compiler_t* compiler) {
    printf("=== Contract Compilation ===\n");

    synor_error_t err;
    uint8_t* wasm;
    size_t wasm_len;
    create_minimal_wasm(&wasm, &wasm_len);

    synor_compile_options_t options = {
        .optimization_level = SYNOR_OPTIMIZATION_SIZE,
        .use_wasm_opt = true,
        .validate = true,
        .extract_metadata = true,
        .generate_abi = true,
        .strip_options = {
            .strip_debug = true,
            .strip_producers = true,
            .strip_names = true,
            .strip_custom = true,
            .strip_unused = true
        }
    };

    synor_compile_result_t* result = NULL;
    err = synor_compile(compiler, wasm, wasm_len, &options, &result);
    free(wasm);

    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to compile contract\n");
        return;
    }

    printf("Compilation result:\n");
    printf("  Contract ID: %s\n", synor_compile_result_get_contract_id(result));
    printf("  Code hash: %s\n", synor_compile_result_get_code_hash(result));
    printf("  Original size: %zu bytes\n", synor_compile_result_get_original_size(result));
    printf("  Optimized size: %zu bytes\n", synor_compile_result_get_optimized_size(result));
    printf("  Size reduction: %.1f%%\n", synor_compile_result_get_size_reduction(result));
    printf("  Estimated deploy gas: %lu\n", synor_compile_result_get_estimated_deploy_gas(result));

    // Get metadata if available
    synor_contract_metadata_t* metadata = synor_compile_result_get_metadata(result);
    if (metadata) {
        printf("\nMetadata:\n");
        printf("  Name: %s\n", synor_metadata_get_name(metadata));
        printf("  Version: %s\n", synor_metadata_get_version(metadata));
        printf("  SDK Version: %s\n", synor_metadata_get_sdk_version(metadata));
    }

    // Get ABI if available
    synor_contract_abi_t* abi = synor_compile_result_get_abi(result);
    if (abi) {
        printf("\nABI:\n");
        printf("  Functions: %zu\n", synor_abi_get_function_count(abi));
        printf("  Events: %zu\n", synor_abi_get_event_count(abi));
        printf("  Errors: %zu\n", synor_abi_get_error_count(abi));
    }

    synor_compile_result_free(result);
    printf("\n");
}

void compilation_modes_example(synor_compiler_t* compiler) {
    printf("=== Compilation Modes ===\n");

    synor_error_t err;
    uint8_t* wasm;
    size_t wasm_len;
    create_minimal_wasm(&wasm, &wasm_len);

    // Development mode: fast compilation, debugging support
    printf("Development mode:\n");
    synor_compile_result_t* dev_result = NULL;
    err = synor_contracts_compile_dev(compiler, wasm, wasm_len, &dev_result);
    if (err == SYNOR_OK) {
        printf("  Size: %zu bytes\n", synor_compile_result_get_optimized_size(dev_result));
        printf("  Optimization: none\n");
    }

    // Production mode: maximum optimization
    printf("\nProduction mode:\n");
    synor_compile_result_t* prod_result = NULL;
    err = synor_contracts_compile_production(compiler, wasm, wasm_len, &prod_result);
    if (err == SYNOR_OK) {
        printf("  Size: %zu bytes\n", synor_compile_result_get_optimized_size(prod_result));
        printf("  Optimization: aggressive\n");
        if (dev_result) {
            printf("  Size savings: %zu bytes\n",
                   synor_compile_result_get_optimized_size(dev_result) -
                   synor_compile_result_get_optimized_size(prod_result));
        }
        synor_compile_result_free(prod_result);
    }

    if (dev_result) synor_compile_result_free(dev_result);

    // Custom optimization levels
    printf("\nOptimization levels:\n");
    synor_optimization_level_t levels[] = {
        SYNOR_OPTIMIZATION_NONE,
        SYNOR_OPTIMIZATION_BASIC,
        SYNOR_OPTIMIZATION_SIZE,
        SYNOR_OPTIMIZATION_AGGRESSIVE
    };
    const char* level_names[] = {"NONE", "BASIC", "SIZE", "AGGRESSIVE"};

    for (int i = 0; i < 4; i++) {
        synor_compile_options_t options = {
            .optimization_level = levels[i]
        };

        synor_compile_result_t* result = NULL;
        err = synor_compile(compiler, wasm, wasm_len, &options, &result);
        if (err == SYNOR_OK) {
            printf("  %s: %zu bytes\n", level_names[i],
                   synor_compile_result_get_optimized_size(result));
            synor_compile_result_free(result);
        }
    }

    free(wasm);
    printf("\n");
}

void abi_example(synor_compiler_t* compiler) {
    printf("=== ABI Operations ===\n");

    synor_error_t err;
    uint8_t* wasm;
    size_t wasm_len;
    create_minimal_wasm(&wasm, &wasm_len);

    // Extract ABI from WASM
    synor_contract_abi_t* abi = NULL;
    err = synor_abi_extract(compiler, wasm, wasm_len, &abi);
    free(wasm);

    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to extract ABI\n");
        return;
    }

    printf("Contract: %s\n", synor_abi_get_name(abi));
    printf("Version: %s\n", synor_abi_get_version(abi));

    // List functions
    size_t func_count = synor_abi_get_function_count(abi);
    if (func_count > 0) {
        printf("\nFunctions:\n");
        for (size_t i = 0; i < func_count; i++) {
            synor_abi_function_t* func = synor_abi_get_function(abi, i);

            char inputs[256] = "";
            size_t input_count = synor_abi_function_get_input_count(func);
            for (size_t j = 0; j < input_count; j++) {
                synor_abi_param_t* param = synor_abi_function_get_input(func, j);
                char temp[64];
                snprintf(temp, sizeof(temp), "%s: %s%s",
                         synor_abi_param_get_name(param),
                         synor_abi_param_get_type_name(param),
                         j < input_count - 1 ? ", " : "");
                strncat(inputs, temp, sizeof(inputs) - strlen(inputs) - 1);
            }

            char outputs[128] = "void";
            size_t output_count = synor_abi_function_get_output_count(func);
            if (output_count > 0) {
                outputs[0] = '\0';
                for (size_t j = 0; j < output_count; j++) {
                    synor_abi_param_t* param = synor_abi_function_get_output(func, j);
                    char temp[64];
                    snprintf(temp, sizeof(temp), "%s%s",
                             synor_abi_param_get_type_name(param),
                             j < output_count - 1 ? ", " : "");
                    strncat(outputs, temp, sizeof(outputs) - strlen(outputs) - 1);
                }
            }

            char modifiers[32] = "";
            if (synor_abi_function_is_view(func)) strcat(modifiers, "view ");
            if (synor_abi_function_is_payable(func)) strcat(modifiers, "payable");

            printf("  %s(%s) -> %s %s\n",
                   synor_abi_function_get_name(func), inputs, outputs, modifiers);
            printf("    Selector: %s\n", synor_abi_function_get_selector(func));
        }
    }

    // List events
    size_t event_count = synor_abi_get_event_count(abi);
    if (event_count > 0) {
        printf("\nEvents:\n");
        for (size_t i = 0; i < event_count; i++) {
            synor_abi_event_t* event = synor_abi_get_event(abi, i);

            char params[256] = "";
            size_t param_count = synor_abi_event_get_param_count(event);
            for (size_t j = 0; j < param_count; j++) {
                synor_abi_event_param_t* param = synor_abi_event_get_param(event, j);
                char temp[64];
                snprintf(temp, sizeof(temp), "%s%s: %s%s",
                         synor_abi_event_param_is_indexed(param) ? "indexed " : "",
                         synor_abi_event_param_get_name(param),
                         synor_abi_event_param_get_type_name(param),
                         j < param_count - 1 ? ", " : "");
                strncat(params, temp, sizeof(params) - strlen(params) - 1);
            }

            printf("  %s(%s)\n", synor_abi_event_get_name(event), params);
            printf("    Topic: %s\n", synor_abi_event_get_topic(event));
        }
    }

    // Encode a function call
    if (func_count > 0) {
        synor_abi_function_t* func = synor_abi_get_function(abi, 0);
        const char* args[] = {"arg1", "arg2"};

        uint8_t* encoded;
        size_t encoded_len;
        err = synor_abi_encode_call(compiler, func, args, 2, &encoded, &encoded_len);
        if (err == SYNOR_OK) {
            printf("\nEncoded call to %s: ", synor_abi_function_get_name(func));
            for (size_t i = 0; i < encoded_len && i < 20; i++) {
                printf("%02x", encoded[i]);
            }
            printf("...\n");

            // Decode a result
            char** decoded;
            size_t decoded_count;
            err = synor_abi_decode_result(compiler, func, encoded, encoded_len,
                                           &decoded, &decoded_count);
            if (err == SYNOR_OK) {
                printf("Decoded result: ");
                for (size_t i = 0; i < decoded_count; i++) {
                    printf("%s%s", decoded[i], i < decoded_count - 1 ? ", " : "");
                }
                printf("\n");
                synor_string_array_free(decoded, decoded_count);
            }

            free(encoded);
        }
    }

    synor_abi_free(abi);
    printf("\n");
}

void analysis_example(synor_compiler_t* compiler) {
    printf("=== Contract Analysis ===\n");

    synor_error_t err;
    uint8_t* wasm;
    size_t wasm_len;
    create_minimal_wasm(&wasm, &wasm_len);

    // Full analysis
    synor_contract_analysis_t* analysis = NULL;
    err = synor_analysis_analyze(compiler, wasm, wasm_len, &analysis);
    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to analyze contract\n");
        free(wasm);
        return;
    }

    // Size breakdown
    synor_size_breakdown_t* size = synor_analysis_get_size_breakdown(analysis);
    if (size) {
        printf("Size breakdown:\n");
        printf("  Code: %zu bytes\n", synor_size_breakdown_get_code(size));
        printf("  Data: %zu bytes\n", synor_size_breakdown_get_data(size));
        printf("  Functions: %zu bytes\n", synor_size_breakdown_get_functions(size));
        printf("  Memory: %zu bytes\n", synor_size_breakdown_get_memory(size));
        printf("  Exports: %zu bytes\n", synor_size_breakdown_get_exports(size));
        printf("  Imports: %zu bytes\n", synor_size_breakdown_get_imports(size));
        printf("  Total: %zu bytes\n", synor_size_breakdown_get_total(size));
    }

    // Function analysis
    size_t func_count = synor_analysis_get_function_count(analysis);
    if (func_count > 0) {
        printf("\nFunction analysis:\n");
        for (size_t i = 0; i < 5 && i < func_count; i++) {
            synor_function_analysis_t* func = synor_analysis_get_function(analysis, i);
            printf("  %s:\n", synor_function_analysis_get_name(func));
            printf("    Size: %zu bytes\n", synor_function_analysis_get_size(func));
            printf("    Instructions: %zu\n", synor_function_analysis_get_instruction_count(func));
            printf("    Locals: %zu\n", synor_function_analysis_get_local_count(func));
            printf("    Exported: %s\n", synor_function_analysis_is_exported(func) ? "true" : "false");
            printf("    Estimated gas: %lu\n", synor_function_analysis_get_estimated_gas(func));
        }
    }

    // Import analysis
    size_t import_count = synor_analysis_get_import_count(analysis);
    if (import_count > 0) {
        printf("\nImports:\n");
        for (size_t i = 0; i < import_count; i++) {
            synor_import_analysis_t* imp = synor_analysis_get_import(analysis, i);
            printf("  %s.%s (%s)\n",
                   synor_import_analysis_get_module(imp),
                   synor_import_analysis_get_name(imp),
                   synor_import_analysis_get_kind(imp));
        }
    }

    // Gas analysis
    synor_gas_analysis_t* gas = synor_analysis_get_gas_analysis(analysis);
    if (gas) {
        printf("\nGas analysis:\n");
        printf("  Deployment: %lu\n", synor_gas_analysis_get_deployment_gas(gas));
        printf("  Memory init: %lu\n", synor_gas_analysis_get_memory_init_gas(gas));
        printf("  Data section: %lu\n", synor_gas_analysis_get_data_section_gas(gas));
    }

    synor_analysis_free(analysis);

    // Extract metadata
    synor_contract_metadata_t* metadata = NULL;
    err = synor_analysis_extract_metadata(compiler, wasm, wasm_len, &metadata);
    if (err == SYNOR_OK) {
        printf("\nContract metadata:\n");
        printf("  Name: %s\n", synor_metadata_get_name(metadata));
        printf("  Version: %s\n", synor_metadata_get_version(metadata));
        printf("  Build timestamp: %s\n", synor_metadata_get_build_timestamp(metadata));
        synor_metadata_free(metadata);
    }

    // Estimate deployment gas
    uint64_t gas_estimate;
    err = synor_analysis_estimate_deploy_gas(compiler, wasm, wasm_len, &gas_estimate);
    if (err == SYNOR_OK) {
        printf("\nEstimated deployment gas: %lu\n", gas_estimate);
    }

    free(wasm);
    printf("\n");
}

void validation_example(synor_compiler_t* compiler) {
    printf("=== Contract Validation ===\n");

    synor_error_t err;
    uint8_t* wasm;
    size_t wasm_len;
    create_minimal_wasm(&wasm, &wasm_len);

    // Full validation
    synor_validation_result_t* result = NULL;
    err = synor_validation_validate(compiler, wasm, wasm_len, &result);
    if (err == SYNOR_OK) {
        printf("Valid: %s\n", synor_validation_result_is_valid(result) ? "true" : "false");
        printf("Exports: %zu\n", synor_validation_result_get_export_count(result));
        printf("Imports: %zu\n", synor_validation_result_get_import_count(result));
        printf("Functions: %zu\n", synor_validation_result_get_function_count(result));
        printf("Memory pages: %zu\n", synor_validation_result_get_memory_pages(result));

        // Print errors
        size_t error_count = synor_validation_result_get_error_count(result);
        if (error_count > 0) {
            printf("\nValidation errors:\n");
            for (size_t i = 0; i < error_count; i++) {
                synor_validation_error_t* error = synor_validation_result_get_error(result, i);
                printf("  [%s] %s\n",
                       synor_validation_error_get_code(error),
                       synor_validation_error_get_message(error));
                const char* location = synor_validation_error_get_location(error);
                if (location) {
                    printf("    at %s\n", location);
                }
            }
        }

        // Print warnings
        size_t warning_count = synor_validation_result_get_warning_count(result);
        if (warning_count > 0) {
            printf("\nWarnings:\n");
            for (size_t i = 0; i < warning_count; i++) {
                printf("  %s\n", synor_validation_result_get_warning(result, i));
            }
        }

        synor_validation_result_free(result);
    }

    // Quick validation
    bool is_valid;
    err = synor_validation_is_valid(compiler, wasm, wasm_len, &is_valid);
    printf("\nQuick validation: %s\n", is_valid ? "true" : "false");

    // Get validation errors only
    synor_validation_error_list_t* errors = NULL;
    err = synor_validation_get_errors(compiler, wasm, wasm_len, &errors);
    if (err == SYNOR_OK) {
        printf("Error count: %zu\n", synor_validation_error_list_count(errors));
        synor_validation_error_list_free(errors);
    }

    // Validate required exports
    const char* required[] = {"init", "execute", "query"};
    bool has_required;
    err = synor_validation_validate_exports(compiler, wasm, wasm_len,
                                             required, 3, &has_required);
    printf("Has required exports: %s\n", has_required ? "true" : "false");

    // Validate memory constraints
    bool memory_valid;
    err = synor_validation_validate_memory(compiler, wasm, wasm_len, 16, &memory_valid);
    printf("Memory within 16 pages: %s\n", memory_valid ? "true" : "false");

    free(wasm);
    printf("\n");
}

void security_example(synor_compiler_t* compiler) {
    printf("=== Security Scanning ===\n");

    synor_error_t err;
    uint8_t* wasm;
    size_t wasm_len;
    create_minimal_wasm(&wasm, &wasm_len);

    synor_security_scan_result_t* security = NULL;
    err = synor_analysis_security_scan(compiler, wasm, wasm_len, &security);
    free(wasm);

    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to scan contract\n");
        return;
    }

    printf("Security score: %d/100\n", synor_security_scan_get_score(security));

    size_t issue_count = synor_security_scan_get_issue_count(security);
    if (issue_count > 0) {
        printf("\nSecurity issues:\n");
        for (size_t i = 0; i < issue_count; i++) {
            synor_security_issue_t* issue = synor_security_scan_get_issue(security, i);
            const char* severity = synor_security_issue_get_severity(issue);
            const char* icon;

            if (strcmp(severity, "critical") == 0) icon = "[CRIT]";
            else if (strcmp(severity, "high") == 0) icon = "[HIGH]";
            else if (strcmp(severity, "medium") == 0) icon = "[MED]";
            else if (strcmp(severity, "low") == 0) icon = "[LOW]";
            else icon = "[???]";

            printf("%s [%s] %s\n", icon,
                   synor_security_issue_get_severity(issue),
                   synor_security_issue_get_type(issue));
            printf("   %s\n", synor_security_issue_get_description(issue));

            const char* location = synor_security_issue_get_location(issue);
            if (location) {
                printf("   at %s\n", location);
            }
        }
    } else {
        printf("No security issues found!\n");
    }

    size_t rec_count = synor_security_scan_get_recommendation_count(security);
    if (rec_count > 0) {
        printf("\nRecommendations:\n");
        for (size_t i = 0; i < rec_count; i++) {
            printf("  • %s\n", synor_security_scan_get_recommendation(security, i));
        }
    }

    synor_security_scan_result_free(security);
    printf("\n");
}

int main(int argc, char** argv) {
    synor_error_t err;

    // Initialize client
    synor_compiler_config_t config = {
        .api_key = getenv("SYNOR_API_KEY") ? getenv("SYNOR_API_KEY") : "your-api-key",
        .endpoint = "https://compiler.synor.io/v1",
        .timeout_ms = 60000,
        .retries = 3,
        .debug = false,
        .default_optimization_level = SYNOR_OPTIMIZATION_SIZE,
        .max_contract_size = 256 * 1024,
        .use_wasm_opt = true,
        .validate = true,
        .extract_metadata = true,
        .generate_abi = true
    };

    synor_compiler_t* compiler = NULL;
    err = synor_compiler_init(&config, &compiler);
    if (err != SYNOR_OK) {
        fprintf(stderr, "Failed to initialize compiler client: %s\n", synor_error_string(err));
        return 1;
    }

    // Check service health
    bool healthy;
    err = synor_compiler_health_check(compiler, &healthy);
    printf("Service healthy: %s\n\n", healthy ? "true" : "false");

    // Run examples
    compile_contract_example(compiler);
    compilation_modes_example(compiler);
    abi_example(compiler);
    analysis_example(compiler);
    validation_example(compiler);
    security_example(compiler);

    // Cleanup
    synor_compiler_free(compiler);

    return 0;
}
