package io.synor.examples

import io.synor.compiler.*
import io.synor.compiler.types.*
import kotlinx.coroutines.runBlocking

/**
 * Synor Compiler SDK Examples for Kotlin
 *
 * Demonstrates smart contract compilation and analysis:
 * - WASM contract compilation and optimization
 * - ABI extraction and encoding
 * - Contract analysis and security scanning
 * - Validation and verification
 */
fun main() = runBlocking {
    // Initialize client
    val config = CompilerConfig(
        apiKey = System.getenv("SYNOR_API_KEY") ?: "your-api-key",
        endpoint = "https://compiler.synor.io/v1",
        timeout = 60_000,
        retries = 3,
        debug = false,
        defaultOptimizationLevel = OptimizationLevel.SIZE,
        maxContractSize = 256 * 1024,
        useWasmOpt = true,
        validate = true,
        extractMetadata = true,
        generateAbi = true
    )

    val compiler = SynorCompiler(config)

    try {
        // Check service health
        val healthy = compiler.healthCheck()
        println("Service healthy: $healthy\n")

        // Run examples
        compileContractExample(compiler)
        compilationModesExample(compiler)
        abiExample(compiler)
        analysisExample(compiler)
        validationExample(compiler)
        securityExample(compiler)
    } finally {
        compiler.close()
    }
}

/**
 * Create a minimal valid WASM module for testing.
 */
fun createMinimalWasm(): ByteArray {
    return byteArrayOf(
        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
    )
}

suspend fun compileContractExample(compiler: SynorCompiler) {
    println("=== Contract Compilation ===")

    val wasm = createMinimalWasm()

    val result = compiler.compile(
        wasm,
        CompileOptions(
            optimizationLevel = OptimizationLevel.SIZE,
            useWasmOpt = true,
            validate = true,
            extractMetadata = true,
            generateAbi = true,
            stripOptions = StripOptions(
                stripDebug = true,
                stripProducers = true,
                stripNames = true,
                stripCustom = true,
                stripUnused = true,
                preserveSections = emptyList()
            )
        )
    )

    println("Compilation result:")
    println("  Contract ID: ${result.contractId}")
    println("  Code hash: ${result.codeHash}")
    println("  Original size: ${result.originalSize} bytes")
    println("  Optimized size: ${result.optimizedSize} bytes")
    println("  Size reduction: ${"%.1f".format(result.sizeReduction)}%")
    println("  Estimated deploy gas: ${result.estimatedDeployGas}")

    result.metadata?.let { metadata ->
        println("\nMetadata:")
        println("  Name: ${metadata.name}")
        println("  Version: ${metadata.version}")
        println("  SDK Version: ${metadata.sdkVersion}")
    }

    result.abi?.let { abi ->
        println("\nABI:")
        println("  Functions: ${abi.functions?.size ?: 0}")
        println("  Events: ${abi.events?.size ?: 0}")
        println("  Errors: ${abi.errors?.size ?: 0}")
    }

    println()
}

suspend fun compilationModesExample(compiler: SynorCompiler) {
    println("=== Compilation Modes ===")

    val wasm = createMinimalWasm()

    // Development mode: fast compilation, debugging support
    println("Development mode:")
    val devResult = compiler.contracts.compileDev(wasm)
    println("  Size: ${devResult.optimizedSize} bytes")
    println("  Optimization: none")

    // Production mode: maximum optimization
    println("\nProduction mode:")
    val prodResult = compiler.contracts.compileProduction(wasm)
    println("  Size: ${prodResult.optimizedSize} bytes")
    println("  Optimization: aggressive")
    println("  Size savings: ${devResult.optimizedSize - prodResult.optimizedSize} bytes")

    // Custom optimization levels
    println("\nOptimization levels:")
    val levels = listOf(
        OptimizationLevel.NONE,
        OptimizationLevel.BASIC,
        OptimizationLevel.SIZE,
        OptimizationLevel.AGGRESSIVE
    )

    for (level in levels) {
        val result = compiler.compile(
            wasm,
            CompileOptions(optimizationLevel = level)
        )
        println("  $level: ${result.optimizedSize} bytes")
    }

    println()
}

suspend fun abiExample(compiler: SynorCompiler) {
    println("=== ABI Operations ===")

    val wasm = createMinimalWasm()

    // Extract ABI from WASM
    val abi = compiler.abi.extract(wasm)
    println("Contract: ${abi.name}")
    println("Version: ${abi.version}")

    // List functions
    abi.functions?.takeIf { it.isNotEmpty() }?.let { functions ->
        println("\nFunctions:")
        for (func in functions) {
            val inputs = func.inputs?.joinToString(", ") { "${it.name}: ${it.type.typeName}" } ?: ""
            val outputs = func.outputs?.joinToString(", ") { it.type.typeName } ?: "void"
            val modifiers = buildList {
                if (func.view) add("view")
                if (func.payable) add("payable")
            }.joinToString(" ")

            println("  ${func.name}($inputs) -> $outputs $modifiers")
            println("    Selector: ${func.selector}")
        }
    }

    // List events
    abi.events?.takeIf { it.isNotEmpty() }?.let { events ->
        println("\nEvents:")
        for (event in events) {
            val params = event.params?.joinToString(", ") {
                "${if (it.indexed) "indexed " else ""}${it.name}: ${it.type.typeName}"
            } ?: ""
            println("  ${event.name}($params)")
            println("    Topic: ${event.topic}")
        }
    }

    // Encode a function call
    abi.functions?.firstOrNull()?.let { func ->
        val encoded = compiler.abi.encodeCall(func, listOf("arg1", "arg2"))
        println("\nEncoded call to ${func.name}: $encoded")

        // Decode a result
        val decoded = compiler.abi.decodeResult(func, encoded)
        println("Decoded result: $decoded")
    }

    println()
}

suspend fun analysisExample(compiler: SynorCompiler) {
    println("=== Contract Analysis ===")

    val wasm = createMinimalWasm()

    // Full analysis
    val analysis = compiler.analysis.analyze(wasm)

    // Size breakdown
    analysis.sizeBreakdown?.let { size ->
        println("Size breakdown:")
        println("  Code: ${size.code} bytes")
        println("  Data: ${size.data} bytes")
        println("  Functions: ${size.functions} bytes")
        println("  Memory: ${size.memory} bytes")
        println("  Exports: ${size.exports} bytes")
        println("  Imports: ${size.imports} bytes")
        println("  Total: ${size.total} bytes")
    }

    // Function analysis
    analysis.functions?.takeIf { it.isNotEmpty() }?.let { functions ->
        println("\nFunction analysis:")
        for (func in functions.take(5)) {
            println("  ${func.name}:")
            println("    Size: ${func.size} bytes")
            println("    Instructions: ${func.instructionCount}")
            println("    Locals: ${func.localCount}")
            println("    Exported: ${func.exported}")
            println("    Estimated gas: ${func.estimatedGas}")
        }
    }

    // Import analysis
    analysis.imports?.takeIf { it.isNotEmpty() }?.let { imports ->
        println("\nImports:")
        for (imp in imports) {
            println("  ${imp.module}.${imp.name} (${imp.kind})")
        }
    }

    // Gas analysis
    analysis.gasAnalysis?.let { gas ->
        println("\nGas analysis:")
        println("  Deployment: ${gas.deploymentGas}")
        println("  Memory init: ${gas.memoryInitGas}")
        println("  Data section: ${gas.dataSectionGas}")
    }

    // Extract metadata
    val metadata = compiler.analysis.extractMetadata(wasm)
    println("\nContract metadata:")
    println("  Name: ${metadata.name}")
    println("  Version: ${metadata.version}")
    println("  Build timestamp: ${metadata.buildTimestamp}")

    // Estimate deployment gas
    val gasEstimate = compiler.analysis.estimateDeployGas(wasm)
    println("\nEstimated deployment gas: $gasEstimate")

    println()
}

suspend fun validationExample(compiler: SynorCompiler) {
    println("=== Contract Validation ===")

    val wasm = createMinimalWasm()

    // Full validation
    val result = compiler.validation.validate(wasm)
    println("Valid: ${result.valid}")
    println("Exports: ${result.exportCount}")
    println("Imports: ${result.importCount}")
    println("Functions: ${result.functionCount}")
    println("Memory pages: ${result.memoryPages}")

    result.errors?.takeIf { it.isNotEmpty() }?.let { errors ->
        println("\nValidation errors:")
        for (error in errors) {
            println("  [${error.code}] ${error.message}")
            error.location?.let { println("    at $it") }
        }
    }

    result.warnings?.takeIf { it.isNotEmpty() }?.let { warnings ->
        println("\nWarnings:")
        for (warning in warnings) {
            println("  $warning")
        }
    }

    // Quick validation
    val isValid = compiler.validation.isValid(wasm)
    println("\nQuick validation: $isValid")

    // Get validation errors only
    val errors = compiler.validation.getErrors(wasm)
    println("Error count: ${errors.size}")

    // Validate required exports
    val hasRequired = compiler.validation.validateExports(
        wasm,
        listOf("init", "execute", "query")
    )
    println("Has required exports: $hasRequired")

    // Validate memory constraints
    val memoryValid = compiler.validation.validateMemory(wasm, maxPages = 16)
    println("Memory within 16 pages: $memoryValid")

    println()
}

suspend fun securityExample(compiler: SynorCompiler) {
    println("=== Security Scanning ===")

    val wasm = createMinimalWasm()

    val security = compiler.analysis.securityScan(wasm)

    println("Security score: ${security.score}/100")

    security.issues?.takeIf { it.isNotEmpty() }?.let { issues ->
        println("\nSecurity issues:")
        val severityIcons = mapOf(
            "critical" to "[CRIT]",
            "high" to "[HIGH]",
            "medium" to "[MED]",
            "low" to "[LOW]"
        )
        for (issue in issues) {
            val icon = severityIcons[issue.severity.lowercase()] ?: "[???]"
            println("$icon [${issue.severity.uppercase()}] ${issue.type}")
            println("   ${issue.description}")
            issue.location?.let { println("   at $it") }
        }
    } ?: println("No security issues found!")

    security.recommendations?.takeIf { it.isNotEmpty() }?.let { recommendations ->
        println("\nRecommendations:")
        for (rec in recommendations) {
            println("  • $rec")
        }
    }

    println()
}
