import Foundation
import SynorCompiler

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

@main
struct CompilerExample {
    static func main() async throws {
        // Initialize client
        let config = CompilerConfig(
            apiKey: ProcessInfo.processInfo.environment["SYNOR_API_KEY"] ?? "your-api-key",
            endpoint: "https://compiler.synor.io/v1",
            timeout: 60,
            retries: 3,
            debug: false,
            defaultOptimizationLevel: .size,
            maxContractSize: 256 * 1024,
            useWasmOpt: true,
            validate: true,
            extractMetadata: true,
            generateAbi: true
        )

        let compiler = SynorCompiler(config: config)

        do {
            // Check service health
            let healthy = try await compiler.healthCheck()
            print("Service healthy: \(healthy)\n")

            // Run examples
            try await compileContractExample(compiler: compiler)
            try await compilationModesExample(compiler: compiler)
            try await abiExample(compiler: compiler)
            try await analysisExample(compiler: compiler)
            try await validationExample(compiler: compiler)
            try await securityExample(compiler: compiler)
        } catch {
            print("Error: \(error)")
        }

        await compiler.close()
    }

    /// Create a minimal valid WASM module for testing.
    static func createMinimalWasm() -> Data {
        return Data([
            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
        ])
    }

    static func compileContractExample(compiler: SynorCompiler) async throws {
        print("=== Contract Compilation ===")

        let wasm = createMinimalWasm()

        let result = try await compiler.compile(
            wasm: wasm,
            options: CompileOptions(
                optimizationLevel: .size,
                useWasmOpt: true,
                validate: true,
                extractMetadata: true,
                generateAbi: true,
                stripOptions: StripOptions(
                    stripDebug: true,
                    stripProducers: true,
                    stripNames: true,
                    stripCustom: true,
                    stripUnused: true,
                    preserveSections: []
                )
            )
        )

        print("Compilation result:")
        print("  Contract ID: \(result.contractId)")
        print("  Code hash: \(result.codeHash)")
        print("  Original size: \(result.originalSize) bytes")
        print("  Optimized size: \(result.optimizedSize) bytes")
        print("  Size reduction: \(String(format: "%.1f", result.sizeReduction))%")
        print("  Estimated deploy gas: \(result.estimatedDeployGas)")

        if let metadata = result.metadata {
            print("\nMetadata:")
            print("  Name: \(metadata.name)")
            print("  Version: \(metadata.version)")
            print("  SDK Version: \(metadata.sdkVersion)")
        }

        if let abi = result.abi {
            print("\nABI:")
            print("  Functions: \(abi.functions?.count ?? 0)")
            print("  Events: \(abi.events?.count ?? 0)")
            print("  Errors: \(abi.errors?.count ?? 0)")
        }

        print()
    }

    static func compilationModesExample(compiler: SynorCompiler) async throws {
        print("=== Compilation Modes ===")

        let wasm = createMinimalWasm()

        // Development mode: fast compilation, debugging support
        print("Development mode:")
        let devResult = try await compiler.contracts.compileDev(wasm: wasm)
        print("  Size: \(devResult.optimizedSize) bytes")
        print("  Optimization: none")

        // Production mode: maximum optimization
        print("\nProduction mode:")
        let prodResult = try await compiler.contracts.compileProduction(wasm: wasm)
        print("  Size: \(prodResult.optimizedSize) bytes")
        print("  Optimization: aggressive")
        print("  Size savings: \(devResult.optimizedSize - prodResult.optimizedSize) bytes")

        // Custom optimization levels
        print("\nOptimization levels:")
        let levels: [OptimizationLevel] = [.none, .basic, .size, .aggressive]

        for level in levels {
            let result = try await compiler.compile(
                wasm: wasm,
                options: CompileOptions(optimizationLevel: level)
            )
            print("  \(level): \(result.optimizedSize) bytes")
        }

        print()
    }

    static func abiExample(compiler: SynorCompiler) async throws {
        print("=== ABI Operations ===")

        let wasm = createMinimalWasm()

        // Extract ABI from WASM
        let abi = try await compiler.abi.extract(wasm: wasm)
        print("Contract: \(abi.name)")
        print("Version: \(abi.version)")

        // List functions
        if let functions = abi.functions, !functions.isEmpty {
            print("\nFunctions:")
            for function in functions {
                let inputs = function.inputs?.map { "\($0.name): \($0.type.typeName)" }.joined(separator: ", ") ?? ""
                let outputs = function.outputs?.map { $0.type.typeName }.joined(separator: ", ") ?? "void"
                var modifiers: [String] = []
                if function.view { modifiers.append("view") }
                if function.payable { modifiers.append("payable") }

                print("  \(function.name)(\(inputs)) -> \(outputs) \(modifiers.joined(separator: " "))")
                print("    Selector: \(function.selector)")
            }
        }

        // List events
        if let events = abi.events, !events.isEmpty {
            print("\nEvents:")
            for event in events {
                let params = event.params?.map { p in
                    "\(p.indexed ? "indexed " : "")\(p.name): \(p.type.typeName)"
                }.joined(separator: ", ") ?? ""
                print("  \(event.name)(\(params))")
                print("    Topic: \(event.topic)")
            }
        }

        // Encode a function call
        if let function = abi.functions?.first {
            let encoded = try await compiler.abi.encodeCall(function: function, args: ["arg1", "arg2"])
            print("\nEncoded call to \(function.name): \(encoded)")

            // Decode a result
            let decoded = try await compiler.abi.decodeResult(function: function, data: encoded)
            print("Decoded result: \(decoded)")
        }

        print()
    }

    static func analysisExample(compiler: SynorCompiler) async throws {
        print("=== Contract Analysis ===")

        let wasm = createMinimalWasm()

        // Full analysis
        let analysis = try await compiler.analysis.analyze(wasm: wasm)

        // Size breakdown
        if let size = analysis.sizeBreakdown {
            print("Size breakdown:")
            print("  Code: \(size.code) bytes")
            print("  Data: \(size.data) bytes")
            print("  Functions: \(size.functions) bytes")
            print("  Memory: \(size.memory) bytes")
            print("  Exports: \(size.exports) bytes")
            print("  Imports: \(size.imports) bytes")
            print("  Total: \(size.total) bytes")
        }

        // Function analysis
        if let functions = analysis.functions, !functions.isEmpty {
            print("\nFunction analysis:")
            for function in functions.prefix(5) {
                print("  \(function.name):")
                print("    Size: \(function.size) bytes")
                print("    Instructions: \(function.instructionCount)")
                print("    Locals: \(function.localCount)")
                print("    Exported: \(function.exported)")
                print("    Estimated gas: \(function.estimatedGas)")
            }
        }

        // Import analysis
        if let imports = analysis.imports, !imports.isEmpty {
            print("\nImports:")
            for imp in imports {
                print("  \(imp.module).\(imp.name) (\(imp.kind))")
            }
        }

        // Gas analysis
        if let gas = analysis.gasAnalysis {
            print("\nGas analysis:")
            print("  Deployment: \(gas.deploymentGas)")
            print("  Memory init: \(gas.memoryInitGas)")
            print("  Data section: \(gas.dataSectionGas)")
        }

        // Extract metadata
        let metadata = try await compiler.analysis.extractMetadata(wasm: wasm)
        print("\nContract metadata:")
        print("  Name: \(metadata.name)")
        print("  Version: \(metadata.version)")
        print("  Build timestamp: \(metadata.buildTimestamp)")

        // Estimate deployment gas
        let gasEstimate = try await compiler.analysis.estimateDeployGas(wasm: wasm)
        print("\nEstimated deployment gas: \(gasEstimate)")

        print()
    }

    static func validationExample(compiler: SynorCompiler) async throws {
        print("=== Contract Validation ===")

        let wasm = createMinimalWasm()

        // Full validation
        let result = try await compiler.validation.validate(wasm: wasm)
        print("Valid: \(result.valid)")
        print("Exports: \(result.exportCount)")
        print("Imports: \(result.importCount)")
        print("Functions: \(result.functionCount)")
        print("Memory pages: \(result.memoryPages)")

        if let errors = result.errors, !errors.isEmpty {
            print("\nValidation errors:")
            for error in errors {
                print("  [\(error.code)] \(error.message)")
                if let location = error.location {
                    print("    at \(location)")
                }
            }
        }

        if let warnings = result.warnings, !warnings.isEmpty {
            print("\nWarnings:")
            for warning in warnings {
                print("  \(warning)")
            }
        }

        // Quick validation
        let isValid = try await compiler.validation.isValid(wasm: wasm)
        print("\nQuick validation: \(isValid)")

        // Get validation errors only
        let errors = try await compiler.validation.getErrors(wasm: wasm)
        print("Error count: \(errors.count)")

        // Validate required exports
        let hasRequired = try await compiler.validation.validateExports(
            wasm: wasm,
            required: ["init", "execute", "query"]
        )
        print("Has required exports: \(hasRequired)")

        // Validate memory constraints
        let memoryValid = try await compiler.validation.validateMemory(wasm: wasm, maxPages: 16)
        print("Memory within 16 pages: \(memoryValid)")

        print()
    }

    static func securityExample(compiler: SynorCompiler) async throws {
        print("=== Security Scanning ===")

        let wasm = createMinimalWasm()

        let security = try await compiler.analysis.securityScan(wasm: wasm)

        print("Security score: \(security.score)/100")

        if let issues = security.issues, !issues.isEmpty {
            print("\nSecurity issues:")
            let severityIcons: [String: String] = [
                "critical": "[CRIT]",
                "high": "[HIGH]",
                "medium": "[MED]",
                "low": "[LOW]"
            ]
            for issue in issues {
                let icon = severityIcons[issue.severity.lowercased()] ?? "[???]"
                print("\(icon) [\(issue.severity.uppercased())] \(issue.type)")
                print("   \(issue.description)")
                if let location = issue.location {
                    print("   at \(location)")
                }
            }
        } else {
            print("No security issues found!")
        }

        if let recommendations = security.recommendations, !recommendations.isEmpty {
            print("\nRecommendations:")
            for rec in recommendations {
                print("  • \(rec)")
            }
        }

        print()
    }
}
