/// Synor ZK SDK Types for Flutter/Dart
///
/// Zero-Knowledge proof systems for ZK-Rollups and privacy.
library synor_zk_types;


/// Proof system backends
enum ProofSystem {
  /// Groth16 - smallest proofs (~192 bytes), fastest verification
  groth16,
  /// PLONK - universal trusted setup, medium proofs (~512 bytes)
  plonk,
  /// STARK - no trusted setup, largest proofs (~50KB)
  stark,
}

extension ProofSystemExtension on ProofSystem {
  String get value {
    switch (this) {
      case ProofSystem.groth16:
        return 'groth16';
      case ProofSystem.plonk:
        return 'plonk';
      case ProofSystem.stark:
        return 'stark';
    }
  }

  static ProofSystem fromString(String value) {
    switch (value) {
      case 'groth16':
        return ProofSystem.groth16;
      case 'plonk':
        return ProofSystem.plonk;
      case 'stark':
        return ProofSystem.stark;
      default:
        return ProofSystem.groth16;
    }
  }
}

/// Circuit types for different operations
enum CircuitType {
  /// Single transfer between accounts
  transfer,
  /// Batch of multiple transfers
  batch,
  /// Deposit from L1 to L2
  deposit,
  /// Withdrawal from L2 to L1
  withdraw,
}

extension CircuitTypeExtension on CircuitType {
  String get value {
    switch (this) {
      case CircuitType.transfer:
        return 'transfer';
      case CircuitType.batch:
        return 'batch';
      case CircuitType.deposit:
        return 'deposit';
      case CircuitType.withdraw:
        return 'withdraw';
    }
  }

  static CircuitType fromString(String value) {
    switch (value) {
      case 'transfer':
        return CircuitType.transfer;
      case 'batch':
        return CircuitType.batch;
      case 'deposit':
        return CircuitType.deposit;
      case 'withdraw':
        return CircuitType.withdraw;
      default:
        return CircuitType.transfer;
    }
  }
}

/// Rollup state
enum RollupState {
  active,
  paused,
  finalizing,
  finalized,
}

/// Proof status
enum ProofStatus {
  generating,
  completed,
  failed,
  verified,
}

/// Zero-knowledge proof
class Proof {
  final String id;
  final ProofSystem system;
  final CircuitType circuitType;
  final String data; // Base64 encoded
  final List<String> publicInputs;
  final int size;
  final int generationTimeMs;
  final int createdAt;

  const Proof({
    required this.id,
    required this.system,
    required this.circuitType,
    required this.data,
    required this.publicInputs,
    required this.size,
    required this.generationTimeMs,
    required this.createdAt,
  });

  factory Proof.fromJson(Map<String, dynamic> json) {
    return Proof(
      id: json['id'] as String,
      system: ProofSystemExtension.fromString(json['system'] as String),
      circuitType: CircuitTypeExtension.fromString(json['circuit_type'] as String),
      data: json['data'] as String,
      publicInputs: List<String>.from(json['public_inputs'] ?? []),
      size: json['size'] as int? ?? 0,
      generationTimeMs: json['generation_time_ms'] as int? ?? 0,
      createdAt: json['created_at'] as int? ?? 0,
    );
  }

  Map<String, dynamic> toJson() => {
        'id': id,
        'system': system.value,
        'circuit_type': circuitType.value,
        'data': data,
        'public_inputs': publicInputs,
        'size': size,
        'generation_time_ms': generationTimeMs,
        'created_at': createdAt,
      };
}

/// Verification key for a circuit
class VerificationKey {
  final String circuitId;
  final CircuitType circuitType;
  final ProofSystem system;
  final String data; // Base64 encoded
  final int size;

  const VerificationKey({
    required this.circuitId,
    required this.circuitType,
    required this.system,
    required this.data,
    required this.size,
  });

  factory VerificationKey.fromJson(Map<String, dynamic> json) {
    return VerificationKey(
      circuitId: json['circuit_id'] as String,
      circuitType: CircuitTypeExtension.fromString(json['circuit_type'] as String),
      system: ProofSystemExtension.fromString(json['system'] as String),
      data: json['data'] as String,
      size: json['size'] as int? ?? 0,
    );
  }
}

/// Proving key for generating proofs
class ProvingKey {
  final String circuitId;
  final CircuitType circuitType;
  final ProofSystem system;
  final String data; // Base64 encoded
  final int size;

  const ProvingKey({
    required this.circuitId,
    required this.circuitType,
    required this.system,
    required this.data,
    required this.size,
  });

  factory ProvingKey.fromJson(Map<String, dynamic> json) {
    return ProvingKey(
      circuitId: json['circuit_id'] as String,
      circuitType: CircuitTypeExtension.fromString(json['circuit_type'] as String),
      system: ProofSystemExtension.fromString(json['system'] as String),
      data: json['data'] as String,
      size: json['size'] as int? ?? 0,
    );
  }
}

/// Circuit configuration
class CircuitConfig {
  final CircuitType type;
  final int? maxBatchSize;
  final int? treeDepth;
  final bool? verifySignatures;
  final Map<String, dynamic>? customConstraints;

  const CircuitConfig({
    required this.type,
    this.maxBatchSize,
    this.treeDepth,
    this.verifySignatures,
    this.customConstraints,
  });

  factory CircuitConfig.fromJson(Map<String, dynamic> json) {
    return CircuitConfig(
      type: CircuitTypeExtension.fromString(json['type'] as String),
      maxBatchSize: json['max_batch_size'] as int?,
      treeDepth: json['tree_depth'] as int?,
      verifySignatures: json['verify_signatures'] as bool?,
      customConstraints: json['custom_constraints'] as Map<String, dynamic>?,
    );
  }

  Map<String, dynamic> toJson() {
    final result = <String, dynamic>{'type': type.value};
    if (maxBatchSize != null) result['max_batch_size'] = maxBatchSize;
    if (treeDepth != null) result['tree_depth'] = treeDepth;
    if (verifySignatures != null) result['verify_signatures'] = verifySignatures;
    if (customConstraints != null) result['custom_constraints'] = customConstraints;
    return result;
  }
}

/// Account state in the rollup
class AccountState {
  final String address;
  final String balance;
  final int nonce;
  final String pubkeyHash;

  const AccountState({
    required this.address,
    required this.balance,
    required this.nonce,
    required this.pubkeyHash,
  });

  factory AccountState.fromJson(Map<String, dynamic> json) {
    return AccountState(
      address: json['address'] as String,
      balance: json['balance'] as String,
      nonce: json['nonce'] as int? ?? 0,
      pubkeyHash: json['pubkey_hash'] as String? ?? '',
    );
  }
}

/// Transfer operation
class Transfer {
  final String from;
  final String to;
  final String amount;
  final String fee;
  final int nonce;
  final String? signature;

  const Transfer({
    required this.from,
    required this.to,
    required this.amount,
    required this.fee,
    required this.nonce,
    this.signature,
  });

  factory Transfer.fromJson(Map<String, dynamic> json) {
    return Transfer(
      from: json['from'] as String,
      to: json['to'] as String,
      amount: json['amount'] as String,
      fee: json['fee'] as String,
      nonce: json['nonce'] as int? ?? 0,
      signature: json['signature'] as String?,
    );
  }

  Map<String, dynamic> toJson() {
    final result = <String, dynamic>{
      'from': from,
      'to': to,
      'amount': amount,
      'fee': fee,
      'nonce': nonce,
    };
    if (signature != null) result['signature'] = signature;
    return result;
  }
}

/// Deposit operation (L1 -> L2)
class Deposit {
  final String l1TxHash;
  final String recipient;
  final String amount;
  final String? token;

  const Deposit({
    required this.l1TxHash,
    required this.recipient,
    required this.amount,
    this.token,
  });

  factory Deposit.fromJson(Map<String, dynamic> json) {
    return Deposit(
      l1TxHash: json['l1_tx_hash'] as String,
      recipient: json['recipient'] as String,
      amount: json['amount'] as String,
      token: json['token'] as String?,
    );
  }

  Map<String, dynamic> toJson() {
    final result = <String, dynamic>{
      'l1_tx_hash': l1TxHash,
      'recipient': recipient,
      'amount': amount,
    };
    if (token != null) result['token'] = token;
    return result;
  }
}

/// Withdrawal operation (L2 -> L1)
class Withdrawal {
  final String sender;
  final String recipient;
  final String amount;
  final String? token;
  final int nonce;
  final String? signature;

  const Withdrawal({
    required this.sender,
    required this.recipient,
    required this.amount,
    this.token,
    required this.nonce,
    this.signature,
  });

  factory Withdrawal.fromJson(Map<String, dynamic> json) {
    return Withdrawal(
      sender: json['sender'] as String,
      recipient: json['recipient'] as String,
      amount: json['amount'] as String,
      token: json['token'] as String?,
      nonce: json['nonce'] as int? ?? 0,
      signature: json['signature'] as String?,
    );
  }

  Map<String, dynamic> toJson() {
    final result = <String, dynamic>{
      'sender': sender,
      'recipient': recipient,
      'amount': amount,
      'nonce': nonce,
    };
    if (token != null) result['token'] = token;
    if (signature != null) result['signature'] = signature;
    return result;
  }
}

/// Rollup batch
class Batch {
  final int batchNumber;
  final String prevStateRoot;
  final String newStateRoot;
  final List<Transfer> transfers;
  final List<Deposit> deposits;
  final List<Withdrawal> withdrawals;
  final Proof? proof;
  final int timestamp;

  const Batch({
    required this.batchNumber,
    required this.prevStateRoot,
    required this.newStateRoot,
    required this.transfers,
    required this.deposits,
    required this.withdrawals,
    this.proof,
    required this.timestamp,
  });

  factory Batch.fromJson(Map<String, dynamic> json) {
    return Batch(
      batchNumber: json['batch_number'] as int,
      prevStateRoot: json['prev_state_root'] as String,
      newStateRoot: json['new_state_root'] as String,
      transfers: (json['transfers'] as List?)
              ?.map((t) => Transfer.fromJson(t as Map<String, dynamic>))
              .toList() ??
          [],
      deposits: (json['deposits'] as List?)
              ?.map((d) => Deposit.fromJson(d as Map<String, dynamic>))
              .toList() ??
          [],
      withdrawals: (json['withdrawals'] as List?)
              ?.map((w) => Withdrawal.fromJson(w as Map<String, dynamic>))
              .toList() ??
          [],
      proof: json['proof'] != null
          ? Proof.fromJson(json['proof'] as Map<String, dynamic>)
          : null,
      timestamp: json['timestamp'] as int? ?? 0,
    );
  }
}

/// Rollup statistics
class RollupStats {
  final int currentBatch;
  final int totalTransactions;
  final int totalProofs;
  final int avgProofTimeMs;
  final String stateRoot;
  final int accountCount;
  final String tvl;

  const RollupStats({
    required this.currentBatch,
    required this.totalTransactions,
    required this.totalProofs,
    required this.avgProofTimeMs,
    required this.stateRoot,
    required this.accountCount,
    required this.tvl,
  });

  factory RollupStats.fromJson(Map<String, dynamic> json) {
    return RollupStats(
      currentBatch: json['current_batch'] as int,
      totalTransactions: json['total_transactions'] as int? ?? 0,
      totalProofs: json['total_proofs'] as int? ?? 0,
      avgProofTimeMs: json['avg_proof_time_ms'] as int? ?? 0,
      stateRoot: json['state_root'] as String,
      accountCount: json['account_count'] as int? ?? 0,
      tvl: json['tvl'] as String? ?? '0',
    );
  }
}

/// Proof generation request
class ProofRequest {
  final CircuitType circuitType;
  final List<String> publicInputs;
  final List<String> privateInputs;
  final ProofSystem? system;

  const ProofRequest({
    required this.circuitType,
    required this.publicInputs,
    required this.privateInputs,
    this.system,
  });

  Map<String, dynamic> toJson() {
    final result = <String, dynamic>{
      'circuit_type': circuitType.value,
      'public_inputs': publicInputs,
      'private_inputs': privateInputs,
    };
    if (system != null) result['system'] = system!.value;
    return result;
  }
}

/// Proof verification result
class VerificationResult {
  final bool valid;
  final int verificationTimeMs;
  final String? error;

  const VerificationResult({
    required this.valid,
    required this.verificationTimeMs,
    this.error,
  });

  factory VerificationResult.fromJson(Map<String, dynamic> json) {
    return VerificationResult(
      valid: json['valid'] as bool,
      verificationTimeMs: json['verification_time_ms'] as int? ?? 0,
      error: json['error'] as String?,
    );
  }
}

/// Merkle proof for state inclusion
class MerkleProof {
  final String leaf;
  final List<String> path;
  final List<int> indices;
  final String root;

  const MerkleProof({
    required this.leaf,
    required this.path,
    required this.indices,
    required this.root,
  });

  factory MerkleProof.fromJson(Map<String, dynamic> json) {
    return MerkleProof(
      leaf: json['leaf'] as String,
      path: List<String>.from(json['path']),
      indices: List<int>.from(json['indices']),
      root: json['root'] as String,
    );
  }

  Map<String, dynamic> toJson() => {
        'leaf': leaf,
        'path': path,
        'indices': indices,
        'root': root,
      };
}

/// Trusted setup ceremony contribution
class CeremonyContribution {
  final String contributorId;
  final String hash;
  final int timestamp;
  final bool verified;

  const CeremonyContribution({
    required this.contributorId,
    required this.hash,
    required this.timestamp,
    required this.verified,
  });

  factory CeremonyContribution.fromJson(Map<String, dynamic> json) {
    return CeremonyContribution(
      contributorId: json['contributor_id'] as String,
      hash: json['hash'] as String,
      timestamp: json['timestamp'] as int? ?? 0,
      verified: json['verified'] as bool? ?? false,
    );
  }
}

/// Trusted setup ceremony
class TrustedSetup {
  final String id;
  final CircuitType circuitType;
  final ProofSystem system;
  final int contributionCount;
  final String latestHash;
  final bool complete;
  final List<CeremonyContribution> contributions;

  const TrustedSetup({
    required this.id,
    required this.circuitType,
    required this.system,
    required this.contributionCount,
    required this.latestHash,
    required this.complete,
    required this.contributions,
  });

  factory TrustedSetup.fromJson(Map<String, dynamic> json) {
    return TrustedSetup(
      id: json['id'] as String,
      circuitType: CircuitTypeExtension.fromString(json['circuit_type'] as String),
      system: ProofSystemExtension.fromString(json['system'] as String),
      contributionCount: json['contribution_count'] as int? ?? 0,
      latestHash: json['latest_hash'] as String? ?? '',
      complete: json['complete'] as bool? ?? false,
      contributions: (json['contributions'] as List?)
              ?.map((c) => CeremonyContribution.fromJson(c as Map<String, dynamic>))
              .toList() ??
          [],
    );
  }
}

/// ZK SDK configuration
class ZkConfig {
  final String apiKey;
  final String endpoint;
  final String wsEndpoint;
  final Duration timeout;
  final int retries;
  final ProofSystem defaultProofSystem;
  final bool debug;

  const ZkConfig({
    required this.apiKey,
    this.endpoint = 'https://zk.synor.io/v1',
    this.wsEndpoint = 'wss://zk.synor.io/v1/ws',
    this.timeout = const Duration(seconds: 60),
    this.retries = 3,
    this.defaultProofSystem = ProofSystem.groth16,
    this.debug = false,
  });
}

/// ZK SDK error
class ZkError implements Exception {
  final String message;
  final String? code;
  final int? status;

  const ZkError(this.message, {this.code, this.status});

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

/// Proof system characteristics
class ProofSystemInfo {
  final String name;
  final int proofSize;
  final int verificationTimeMs;
  final bool trustedSetup;
  final bool universal;

  const ProofSystemInfo({
    required this.name,
    required this.proofSize,
    required this.verificationTimeMs,
    required this.trustedSetup,
    required this.universal,
  });
}

/// Get proof system info
ProofSystemInfo getProofSystemInfo(ProofSystem system) {
  switch (system) {
    case ProofSystem.groth16:
      return const ProofSystemInfo(
        name: 'Groth16',
        proofSize: 192,
        verificationTimeMs: 10,
        trustedSetup: true,
        universal: false,
      );
    case ProofSystem.plonk:
      return const ProofSystemInfo(
        name: 'PLONK',
        proofSize: 512,
        verificationTimeMs: 15,
        trustedSetup: true,
        universal: true,
      );
    case ProofSystem.stark:
      return const ProofSystemInfo(
        name: 'STARK',
        proofSize: 50000,
        verificationTimeMs: 30,
        trustedSetup: false,
        universal: true,
      );
  }
}

/// Constants
const int maxBatchSize = 1000;
const int stateTreeDepth = 32;
const int proofExpiryBlocks = 100;
