# frozen_string_literal: true

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

require 'synor/compiler'

class CompilerExample
  def initialize(compiler)
    @compiler = compiler
  end

  # Creates a minimal valid WASM module for testing
  def create_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, # "add"
      # Code section
      0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
    ].pack('C*')
  end

  def run_compile_contract_example
    puts '=== Contract Compilation ==='

    wasm = create_minimal_wasm

    result = @compiler.compile(wasm,
      optimization_level: :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,
        preserve_sections: []
      }
    )

    puts 'Compilation result:'
    puts "  Contract ID: #{result.contract_id}"
    puts "  Code hash: #{result.code_hash}"
    puts "  Original size: #{result.original_size} bytes"
    puts "  Optimized size: #{result.optimized_size} bytes"
    puts "  Size reduction: #{format('%.1f', result.size_reduction)}%"
    puts "  Estimated deploy gas: #{result.estimated_deploy_gas}"

    if result.metadata
      puts "\nMetadata:"
      puts "  Name: #{result.metadata.name}"
      puts "  Version: #{result.metadata.version}"
      puts "  SDK Version: #{result.metadata.sdk_version}"
    end

    if result.abi
      puts "\nABI:"
      puts "  Functions: #{result.abi.functions.length}"
      puts "  Events: #{result.abi.events.length}"
      puts "  Errors: #{result.abi.errors.length}"
    end
    puts
  end

  def run_compilation_modes_example
    puts '=== Compilation Modes ==='

    wasm = create_minimal_wasm

    # Development mode: fast compilation, debugging support
    puts 'Development mode:'
    dev_result = @compiler.contracts.compile_dev(wasm)
    puts "  Size: #{dev_result.optimized_size} bytes"
    puts '  Optimization: none'

    # Production mode: maximum optimization
    puts "\nProduction mode:"
    prod_result = @compiler.contracts.compile_production(wasm)
    puts "  Size: #{prod_result.optimized_size} bytes"
    puts '  Optimization: aggressive'
    puts "  Size savings: #{dev_result.optimized_size - prod_result.optimized_size} bytes"

    # Custom optimization levels
    puts "\nOptimization levels:"
    levels = [
      { level: :none, name: 'NONE' },
      { level: :basic, name: 'BASIC' },
      { level: :size, name: 'SIZE' },
      { level: :aggressive, name: 'AGGRESSIVE' }
    ]

    levels.each do |l|
      result = @compiler.compile(wasm, optimization_level: l[:level])
      puts "  #{l[:name]}: #{result.optimized_size} bytes"
    end
    puts
  end

  def run_abi_example
    puts '=== ABI Operations ==='

    wasm = create_minimal_wasm

    # Extract ABI from WASM
    abi = @compiler.abi.extract(wasm)
    puts "Contract: #{abi.name}"
    puts "Version: #{abi.version}"

    # List functions
    if abi.functions.any?
      puts "\nFunctions:"
      abi.functions.each do |func|
        inputs = func.inputs.map { |p| "#{p.name}: #{p.type.type_name}" }.join(', ')
        outputs = func.outputs.empty? ? 'void' : func.outputs.map { |o| o.type.type_name }.join(', ')

        modifiers = []
        modifiers << 'view' if func.view?
        modifiers << 'payable' if func.payable?
        modifier_str = modifiers.join(' ')

        puts "  #{func.name}(#{inputs}) -> #{outputs} #{modifier_str}"
        puts "    Selector: #{func.selector}"
      end
    end

    # List events
    if abi.events.any?
      puts "\nEvents:"
      abi.events.each do |event|
        params = event.params.map do |param|
          prefix = param.indexed? ? 'indexed ' : ''
          "#{prefix}#{param.name}: #{param.type.type_name}"
        end.join(', ')
        puts "  #{event.name}(#{params})"
        puts "    Topic: #{event.topic}"
      end
    end

    # Encode a function call
    if abi.functions.any?
      func = abi.functions.first
      encoded = @compiler.abi.encode_call(func, %w[arg1 arg2])
      puts "\nEncoded call to #{func.name}: #{encoded}"

      # Decode a result
      decoded = @compiler.abi.decode_result(func, encoded)
      puts "Decoded result: #{decoded}"
    end
    puts
  end

  def run_analysis_example
    puts '=== Contract Analysis ==='

    wasm = create_minimal_wasm

    # Full analysis
    analysis = @compiler.analysis.analyze(wasm)

    # Size breakdown
    if analysis.size_breakdown
      size = analysis.size_breakdown
      puts 'Size breakdown:'
      puts "  Code: #{size.code} bytes"
      puts "  Data: #{size.data} bytes"
      puts "  Functions: #{size.functions} bytes"
      puts "  Memory: #{size.memory} bytes"
      puts "  Exports: #{size.exports} bytes"
      puts "  Imports: #{size.imports} bytes"
      puts "  Total: #{size.total} bytes"
    end

    # Function analysis
    if analysis.functions.any?
      puts "\nFunction analysis:"
      analysis.functions.first(5).each do |func|
        puts "  #{func.name}:"
        puts "    Size: #{func.size} bytes"
        puts "    Instructions: #{func.instruction_count}"
        puts "    Locals: #{func.local_count}"
        puts "    Exported: #{func.exported?}"
        puts "    Estimated gas: #{func.estimated_gas}"
      end
    end

    # Import analysis
    if analysis.imports.any?
      puts "\nImports:"
      analysis.imports.each do |imp|
        puts "  #{imp.module}.#{imp.name} (#{imp.kind})"
      end
    end

    # Gas analysis
    if analysis.gas_analysis
      gas = analysis.gas_analysis
      puts "\nGas analysis:"
      puts "  Deployment: #{gas.deployment_gas}"
      puts "  Memory init: #{gas.memory_init_gas}"
      puts "  Data section: #{gas.data_section_gas}"
    end

    # Extract metadata
    metadata = @compiler.analysis.extract_metadata(wasm)
    puts "\nContract metadata:"
    puts "  Name: #{metadata.name}"
    puts "  Version: #{metadata.version}"
    puts "  Build timestamp: #{metadata.build_timestamp}"

    # Estimate deployment gas
    gas_estimate = @compiler.analysis.estimate_deploy_gas(wasm)
    puts "\nEstimated deployment gas: #{gas_estimate}"
    puts
  end

  def run_validation_example
    puts '=== Contract Validation ==='

    wasm = create_minimal_wasm

    # Full validation
    result = @compiler.validation.validate(wasm)
    puts "Valid: #{result.valid?}"
    puts "Exports: #{result.export_count}"
    puts "Imports: #{result.import_count}"
    puts "Functions: #{result.function_count}"
    puts "Memory pages: #{result.memory_pages}"

    if result.errors.any?
      puts "\nValidation errors:"
      result.errors.each do |error|
        puts "  [#{error.code}] #{error.message}"
        puts "    at #{error.location}" if error.location
      end
    end

    if result.warnings.any?
      puts "\nWarnings:"
      result.warnings.each do |warning|
        puts "  #{warning}"
      end
    end

    # Quick validation
    is_valid = @compiler.validation.valid?(wasm)
    puts "\nQuick validation: #{is_valid}"

    # Get validation errors only
    errors = @compiler.validation.get_errors(wasm)
    puts "Error count: #{errors.length}"

    # Validate required exports
    has_required = @compiler.validation.validate_exports(wasm, %w[init execute query])
    puts "Has required exports: #{has_required}"

    # Validate memory constraints
    memory_valid = @compiler.validation.validate_memory(wasm, 16)
    puts "Memory within 16 pages: #{memory_valid}"
    puts
  end

  def run_security_example
    puts '=== Security Scanning ==='

    wasm = create_minimal_wasm

    security = @compiler.analysis.security_scan(wasm)

    puts "Security score: #{security.score}/100"

    if security.issues.any?
      puts "\nSecurity issues:"
      security.issues.each do |issue|
        icon = case issue.severity
               when 'critical' then '[CRIT]'
               when 'high' then '[HIGH]'
               when 'medium' then '[MED]'
               when 'low' then '[LOW]'
               else '[???]'
               end

        puts "#{icon} [#{issue.severity}] #{issue.type}"
        puts "   #{issue.description}"
        puts "   at #{issue.location}" if issue.location
      end
    else
      puts 'No security issues found!'
    end

    if security.recommendations.any?
      puts "\nRecommendations:"
      security.recommendations.each do |rec|
        puts "  • #{rec}"
      end
    end
    puts
  end
end

# Main execution
if __FILE__ == $PROGRAM_NAME
  # Initialize client
  api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key')
  config = Synor::Compiler::Config.new(
    api_key: api_key,
    endpoint: 'https://compiler.synor.io/v1',
    timeout: 60,
    retries: 3,
    debug: false,
    default_optimization_level: :size,
    max_contract_size: 256 * 1024,
    use_wasm_opt: true,
    validate: true,
    extract_metadata: true,
    generate_abi: true
  )

  compiler = Synor::Compiler::Client.new(config)
  example = CompilerExample.new(compiler)

  begin
    # Check service health
    healthy = compiler.health_check
    puts "Service healthy: #{healthy}\n\n"

    # Run examples
    example.run_compile_contract_example
    example.run_compilation_modes_example
    example.run_abi_example
    example.run_analysis_example
    example.run_validation_example
    example.run_security_example
  rescue StandardError => e
    warn "Error: #{e.message}"
    exit 1
  end
end
