/// Synor Compiler SDK Types
///
/// Smart contract compilation, optimization, and ABI generation.
library synor_compiler_types;

/// Optimization level for WASM compilation.
enum OptimizationLevel {
  /// No optimization.
  none,

  /// Basic optimizations (stripping only).
  basic,

  /// Optimize for size (-Os equivalent).
  size,

  /// Aggressive optimization (-O3 -Os equivalent).
  aggressive,
}

extension OptimizationLevelExtension on OptimizationLevel {
  String toApiString() {
    switch (this) {
      case OptimizationLevel.none:
        return 'none';
      case OptimizationLevel.basic:
        return 'basic';
      case OptimizationLevel.size:
        return 'size';
      case OptimizationLevel.aggressive:
        return 'aggressive';
    }
  }

  static OptimizationLevel fromApiString(String value) {
    switch (value) {
      case 'none':
        return OptimizationLevel.none;
      case 'basic':
        return OptimizationLevel.basic;
      case 'size':
        return OptimizationLevel.size;
      case 'aggressive':
        return OptimizationLevel.aggressive;
      default:
        return OptimizationLevel.size;
    }
  }
}

/// Options for stripping WASM sections.
class StripOptions {
  final bool stripDebug;
  final bool stripProducers;
  final bool stripNames;
  final bool stripCustom;
  final List<String> preserveSections;
  final bool stripUnused;

  const StripOptions({
    this.stripDebug = true,
    this.stripProducers = true,
    this.stripNames = true,
    this.stripCustom = true,
    this.preserveSections = const [],
    this.stripUnused = true,
  });

  factory StripOptions.fromJson(Map<String, dynamic> json) {
    return StripOptions(
      stripDebug: json['strip_debug'] ?? true,
      stripProducers: json['strip_producers'] ?? true,
      stripNames: json['strip_names'] ?? true,
      stripCustom: json['strip_custom'] ?? true,
      preserveSections: List<String>.from(json['preserve_sections'] ?? []),
      stripUnused: json['strip_unused'] ?? true,
    );
  }

  Map<String, dynamic> toJson() => {
        'strip_debug': stripDebug,
        'strip_producers': stripProducers,
        'strip_names': stripNames,
        'strip_custom': stripCustom,
        'preserve_sections': preserveSections,
        'strip_unused': stripUnused,
      };
}

/// Compiler configuration.
class CompilerConfig {
  final String apiKey;
  final String endpoint;
  final int timeout;
  final int retries;
  final bool debug;
  final OptimizationLevel optimizationLevel;
  final StripOptions? stripOptions;
  final int maxContractSize;
  final bool useWasmOpt;
  final bool validate;
  final bool extractMetadata;
  final bool generateAbi;

  const CompilerConfig({
    required this.apiKey,
    this.endpoint = 'https://compiler.synor.io/v1',
    this.timeout = 60000,
    this.retries = 3,
    this.debug = false,
    this.optimizationLevel = OptimizationLevel.size,
    this.stripOptions,
    this.maxContractSize = 256 * 1024,
    this.useWasmOpt = true,
    this.validate = true,
    this.extractMetadata = true,
    this.generateAbi = true,
  });
}

/// Validation error.
class ValidationError {
  final String code;
  final String message;
  final String? location;

  const ValidationError({
    required this.code,
    required this.message,
    this.location,
  });

  factory ValidationError.fromJson(Map<String, dynamic> json) {
    return ValidationError(
      code: json['code'] ?? '',
      message: json['message'] ?? '',
      location: json['location'],
    );
  }
}

/// Validation result.
class ValidationResult {
  final bool valid;
  final List<ValidationError> errors;
  final List<String> warnings;
  final int exportCount;
  final int importCount;
  final int functionCount;
  final List<int?> memoryPages;

  const ValidationResult({
    required this.valid,
    this.errors = const [],
    this.warnings = const [],
    this.exportCount = 0,
    this.importCount = 0,
    this.functionCount = 0,
    this.memoryPages = const [0, null],
  });

  factory ValidationResult.fromJson(Map<String, dynamic> json) {
    return ValidationResult(
      valid: json['valid'] ?? false,
      errors: (json['errors'] as List<dynamic>?)
              ?.map((e) => ValidationError.fromJson(e))
              .toList() ??
          [],
      warnings: List<String>.from(json['warnings'] ?? []),
      exportCount: json['export_count'] ?? 0,
      importCount: json['import_count'] ?? 0,
      functionCount: json['function_count'] ?? 0,
      memoryPages: List<int?>.from(json['memory_pages'] ?? [0, null]),
    );
  }
}

/// Contract metadata.
class ContractMetadata {
  final String? name;
  final String? version;
  final List<String> authors;
  final String? description;
  final String? license;
  final String? repository;
  final int? buildTimestamp;
  final String? rustVersion;
  final String? sdkVersion;
  final Map<String, String> custom;

  const ContractMetadata({
    this.name,
    this.version,
    this.authors = const [],
    this.description,
    this.license,
    this.repository,
    this.buildTimestamp,
    this.rustVersion,
    this.sdkVersion,
    this.custom = const {},
  });

  factory ContractMetadata.fromJson(Map<String, dynamic> json) {
    return ContractMetadata(
      name: json['name'],
      version: json['version'],
      authors: List<String>.from(json['authors'] ?? []),
      description: json['description'],
      license: json['license'],
      repository: json['repository'],
      buildTimestamp: json['build_timestamp'],
      rustVersion: json['rust_version'],
      sdkVersion: json['sdk_version'],
      custom: Map<String, String>.from(json['custom'] ?? {}),
    );
  }
}

/// Type information.
class TypeInfo {
  final String kind;
  final int? size;
  final TypeInfo? element;
  final TypeInfo? inner;
  final List<TypeInfo>? elements;
  final String? name;
  final List<TypeField>? fields;

  const TypeInfo({
    required this.kind,
    this.size,
    this.element,
    this.inner,
    this.elements,
    this.name,
    this.fields,
  });

  factory TypeInfo.fromJson(Map<String, dynamic> json) {
    return TypeInfo(
      kind: json['kind'] ?? 'unknown',
      size: json['size'],
      element: json['element'] != null ? TypeInfo.fromJson(json['element']) : null,
      inner: json['inner'] != null ? TypeInfo.fromJson(json['inner']) : null,
      elements: (json['elements'] as List<dynamic>?)
          ?.map((e) => TypeInfo.fromJson(e))
          .toList(),
      name: json['name'],
      fields: (json['fields'] as List<dynamic>?)
          ?.map((f) => TypeField.fromJson(f))
          .toList(),
    );
  }

  String get typeName {
    switch (kind) {
      case 'u8':
      case 'u16':
      case 'u32':
      case 'u64':
      case 'u128':
      case 'i8':
      case 'i16':
      case 'i32':
      case 'i64':
      case 'i128':
      case 'bool':
      case 'string':
      case 'bytes':
      case 'address':
      case 'hash256':
        return kind;
      case 'fixedBytes':
        return 'bytes${size ?? 0}';
      case 'array':
        return '${element?.typeName ?? ''}[]';
      case 'fixedArray':
        return '${element?.typeName ?? ''}[${size ?? 0}]';
      case 'option':
        return '${inner?.typeName ?? ''}?';
      case 'tuple':
        final names = elements?.map((e) => e.typeName).join(', ') ?? '';
        return '($names)';
      case 'struct':
        return name ?? 'struct';
      default:
        return name ?? 'unknown';
    }
  }
}

/// Type field for structs.
class TypeField {
  final String name;
  final TypeInfo type;

  const TypeField({required this.name, required this.type});

  factory TypeField.fromJson(Map<String, dynamic> json) {
    return TypeField(
      name: json['name'] ?? '',
      type: TypeInfo.fromJson(json['type'] ?? {'kind': 'unknown'}),
    );
  }
}

/// Parameter ABI.
class ParamAbi {
  final String name;
  final TypeInfo type;
  final bool indexed;

  const ParamAbi({
    required this.name,
    required this.type,
    this.indexed = false,
  });

  factory ParamAbi.fromJson(Map<String, dynamic> json) {
    return ParamAbi(
      name: json['name'] ?? '',
      type: TypeInfo.fromJson(json['type'] ?? {'kind': 'unknown'}),
      indexed: json['indexed'] ?? false,
    );
  }
}

/// Function ABI.
class FunctionAbi {
  final String name;
  final String selector;
  final List<ParamAbi> inputs;
  final List<ParamAbi> outputs;
  final bool view;
  final bool payable;
  final String? doc;

  const FunctionAbi({
    required this.name,
    required this.selector,
    this.inputs = const [],
    this.outputs = const [],
    this.view = false,
    this.payable = false,
    this.doc,
  });

  factory FunctionAbi.fromJson(Map<String, dynamic> json) {
    return FunctionAbi(
      name: json['name'] ?? '',
      selector: json['selector'] ?? '',
      inputs: (json['inputs'] as List<dynamic>?)
              ?.map((i) => ParamAbi.fromJson(i))
              .toList() ??
          [],
      outputs: (json['outputs'] as List<dynamic>?)
              ?.map((o) => ParamAbi.fromJson(o))
              .toList() ??
          [],
      view: json['view'] ?? false,
      payable: json['payable'] ?? false,
      doc: json['doc'],
    );
  }
}

/// Event ABI.
class EventAbi {
  final String name;
  final String topic;
  final List<ParamAbi> params;
  final String? doc;

  const EventAbi({
    required this.name,
    required this.topic,
    this.params = const [],
    this.doc,
  });

  factory EventAbi.fromJson(Map<String, dynamic> json) {
    return EventAbi(
      name: json['name'] ?? '',
      topic: json['topic'] ?? '',
      params: (json['params'] as List<dynamic>?)
              ?.map((p) => ParamAbi.fromJson(p))
              .toList() ??
          [],
      doc: json['doc'],
    );
  }
}

/// Error ABI.
class ErrorAbi {
  final String name;
  final String selector;
  final List<ParamAbi> params;
  final String? doc;

  const ErrorAbi({
    required this.name,
    required this.selector,
    this.params = const [],
    this.doc,
  });

  factory ErrorAbi.fromJson(Map<String, dynamic> json) {
    return ErrorAbi(
      name: json['name'] ?? '',
      selector: json['selector'] ?? '',
      params: (json['params'] as List<dynamic>?)
              ?.map((p) => ParamAbi.fromJson(p))
              .toList() ??
          [],
      doc: json['doc'],
    );
  }
}

/// Contract ABI (Application Binary Interface).
class ContractAbi {
  final String name;
  final String version;
  final List<FunctionAbi> functions;
  final List<EventAbi> events;
  final List<ErrorAbi> errors;

  const ContractAbi({
    required this.name,
    required this.version,
    this.functions = const [],
    this.events = const [],
    this.errors = const [],
  });

  factory ContractAbi.fromJson(Map<String, dynamic> json) {
    return ContractAbi(
      name: json['name'] ?? '',
      version: json['version'] ?? '1.0.0',
      functions: (json['functions'] as List<dynamic>?)
              ?.map((f) => FunctionAbi.fromJson(f))
              .toList() ??
          [],
      events: (json['events'] as List<dynamic>?)
              ?.map((e) => EventAbi.fromJson(e))
              .toList() ??
          [],
      errors: (json['errors'] as List<dynamic>?)
              ?.map((e) => ErrorAbi.fromJson(e))
              .toList() ??
          [],
    );
  }

  FunctionAbi? findFunction(String name) {
    return functions.cast<FunctionAbi?>().firstWhere(
          (f) => f?.name == name,
          orElse: () => null,
        );
  }

  FunctionAbi? findBySelector(String selector) {
    return functions.cast<FunctionAbi?>().firstWhere(
          (f) => f?.selector == selector,
          orElse: () => null,
        );
  }
}

/// Compilation result.
class CompilationResult {
  final String contractId;
  final String code;
  final String codeHash;
  final int originalSize;
  final int optimizedSize;
  final double sizeReduction;
  final ContractMetadata? metadata;
  final ContractAbi? abi;
  final int estimatedDeployGas;
  final ValidationResult? validation;
  final List<String> warnings;

  const CompilationResult({
    required this.contractId,
    required this.code,
    required this.codeHash,
    required this.originalSize,
    required this.optimizedSize,
    required this.sizeReduction,
    this.metadata,
    this.abi,
    this.estimatedDeployGas = 0,
    this.validation,
    this.warnings = const [],
  });

  factory CompilationResult.fromJson(Map<String, dynamic> json) {
    return CompilationResult(
      contractId: json['contract_id'] ?? '',
      code: json['code'] ?? '',
      codeHash: json['code_hash'] ?? '',
      originalSize: json['original_size'] ?? 0,
      optimizedSize: json['optimized_size'] ?? 0,
      sizeReduction: (json['size_reduction'] ?? 0).toDouble(),
      metadata: json['metadata'] != null
          ? ContractMetadata.fromJson(json['metadata'])
          : null,
      abi: json['abi'] != null ? ContractAbi.fromJson(json['abi']) : null,
      estimatedDeployGas: json['estimated_deploy_gas'] ?? 0,
      validation: json['validation'] != null
          ? ValidationResult.fromJson(json['validation'])
          : null,
      warnings: List<String>.from(json['warnings'] ?? []),
    );
  }

  String get sizeStats =>
      'Original: $originalSize bytes, Optimized: $optimizedSize bytes, Reduction: ${sizeReduction.toStringAsFixed(1)}%';
}

/// Source mapping entry.
class SourceMapping {
  final int wasmOffset;
  final int line;
  final int column;
  final String? function;

  const SourceMapping({
    required this.wasmOffset,
    required this.line,
    required this.column,
    this.function,
  });

  factory SourceMapping.fromJson(Map<String, dynamic> json) {
    return SourceMapping(
      wasmOffset: json['wasm_offset'] ?? 0,
      line: json['line'] ?? 0,
      column: json['column'] ?? 0,
      function: json['function'],
    );
  }
}

/// Source map.
class SourceMap {
  final String file;
  final List<SourceMapping> mappings;

  const SourceMap({
    required this.file,
    this.mappings = const [],
  });

  factory SourceMap.fromJson(Map<String, dynamic> json) {
    return SourceMap(
      file: json['file'] ?? '',
      mappings: (json['mappings'] as List<dynamic>?)
              ?.map((m) => SourceMapping.fromJson(m))
              .toList() ??
          [],
    );
  }
}

/// Size breakdown.
class SizeBreakdown {
  final int code;
  final int data;
  final int types;
  final int functions;
  final int memory;
  final int table;
  final int exports;
  final int imports;
  final int custom;
  final int total;

  const SizeBreakdown({
    this.code = 0,
    this.data = 0,
    this.types = 0,
    this.functions = 0,
    this.memory = 0,
    this.table = 0,
    this.exports = 0,
    this.imports = 0,
    this.custom = 0,
    this.total = 0,
  });

  factory SizeBreakdown.fromJson(Map<String, dynamic> json) {
    return SizeBreakdown(
      code: json['code'] ?? 0,
      data: json['data'] ?? 0,
      types: json['types'] ?? 0,
      functions: json['functions'] ?? 0,
      memory: json['memory'] ?? 0,
      table: json['table'] ?? 0,
      exports: json['exports'] ?? 0,
      imports: json['imports'] ?? 0,
      custom: json['custom'] ?? 0,
      total: json['total'] ?? 0,
    );
  }
}

/// Function analysis.
class FunctionAnalysis {
  final String name;
  final int size;
  final int instructionCount;
  final int localCount;
  final bool exported;
  final int estimatedGas;

  const FunctionAnalysis({
    required this.name,
    required this.size,
    required this.instructionCount,
    required this.localCount,
    required this.exported,
    required this.estimatedGas,
  });

  factory FunctionAnalysis.fromJson(Map<String, dynamic> json) {
    return FunctionAnalysis(
      name: json['name'] ?? '',
      size: json['size'] ?? 0,
      instructionCount: json['instruction_count'] ?? 0,
      localCount: json['local_count'] ?? 0,
      exported: json['exported'] ?? false,
      estimatedGas: json['estimated_gas'] ?? 0,
    );
  }
}

/// Import analysis.
class ImportAnalysis {
  final String module;
  final String name;
  final String kind;
  final String? signature;

  const ImportAnalysis({
    required this.module,
    required this.name,
    required this.kind,
    this.signature,
  });

  factory ImportAnalysis.fromJson(Map<String, dynamic> json) {
    return ImportAnalysis(
      module: json['module'] ?? '',
      name: json['name'] ?? '',
      kind: json['kind'] ?? 'function',
      signature: json['signature'],
    );
  }
}

/// Security issue.
class SecurityIssue {
  final String severity;
  final String type;
  final String description;
  final String? location;

  const SecurityIssue({
    required this.severity,
    required this.type,
    required this.description,
    this.location,
  });

  factory SecurityIssue.fromJson(Map<String, dynamic> json) {
    return SecurityIssue(
      severity: json['severity'] ?? 'low',
      type: json['type'] ?? '',
      description: json['description'] ?? '',
      location: json['location'],
    );
  }
}

/// Security analysis.
class SecurityAnalysis {
  final int score;
  final List<SecurityIssue> issues;
  final List<String> recommendations;

  const SecurityAnalysis({
    required this.score,
    this.issues = const [],
    this.recommendations = const [],
  });

  factory SecurityAnalysis.fromJson(Map<String, dynamic> json) {
    return SecurityAnalysis(
      score: json['score'] ?? 0,
      issues: (json['issues'] as List<dynamic>?)
              ?.map((i) => SecurityIssue.fromJson(i))
              .toList() ??
          [],
      recommendations: List<String>.from(json['recommendations'] ?? []),
    );
  }
}

/// Gas analysis.
class GasAnalysis {
  final int deploymentGas;
  final Map<String, int> functionGas;
  final int memoryInitGas;
  final int dataSectionGas;

  const GasAnalysis({
    required this.deploymentGas,
    this.functionGas = const {},
    this.memoryInitGas = 0,
    this.dataSectionGas = 0,
  });

  factory GasAnalysis.fromJson(Map<String, dynamic> json) {
    return GasAnalysis(
      deploymentGas: json['deployment_gas'] ?? 0,
      functionGas: Map<String, int>.from(json['function_gas'] ?? {}),
      memoryInitGas: json['memory_init_gas'] ?? 0,
      dataSectionGas: json['data_section_gas'] ?? 0,
    );
  }
}

/// Contract analysis result.
class ContractAnalysis {
  final SizeBreakdown sizeBreakdown;
  final List<FunctionAnalysis> functions;
  final List<ImportAnalysis> imports;
  final SecurityAnalysis? security;
  final GasAnalysis? gasAnalysis;

  const ContractAnalysis({
    required this.sizeBreakdown,
    this.functions = const [],
    this.imports = const [],
    this.security,
    this.gasAnalysis,
  });

  factory ContractAnalysis.fromJson(Map<String, dynamic> json) {
    return ContractAnalysis(
      sizeBreakdown: SizeBreakdown.fromJson(json['size_breakdown'] ?? {}),
      functions: (json['functions'] as List<dynamic>?)
              ?.map((f) => FunctionAnalysis.fromJson(f))
              .toList() ??
          [],
      imports: (json['imports'] as List<dynamic>?)
              ?.map((i) => ImportAnalysis.fromJson(i))
              .toList() ??
          [],
      security: json['security'] != null
          ? SecurityAnalysis.fromJson(json['security'])
          : null,
      gasAnalysis: json['gas_analysis'] != null
          ? GasAnalysis.fromJson(json['gas_analysis'])
          : null,
    );
  }
}

/// Compiler error.
class CompilerError implements Exception {
  final String message;
  final String? code;
  final int? httpStatus;

  const CompilerError(this.message, {this.code, this.httpStatus});

  @override
  String toString() => code != null ? '$message ($code)' : message;
}

/// Constants
const int maxContractSize = 256 * 1024; // 256 KB
const int maxMemoryPages = 16;
