using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Synor.Zk;

/// <summary>Proof system backends</summary>
public enum ProofSystem
{
    /// <summary>Smallest proofs (~192 bytes), fastest verification</summary>
    Groth16,
    /// <summary>Universal trusted setup, medium proofs (~512 bytes)</summary>
    Plonk,
    /// <summary>No trusted setup, largest proofs (~50KB)</summary>
    Stark
}

/// <summary>Circuit types for different operations</summary>
public enum CircuitType
{
    /// <summary>Single transfer between accounts</summary>
    Transfer,
    /// <summary>Batch of multiple transfers</summary>
    Batch,
    /// <summary>Deposit from L1 to L2</summary>
    Deposit,
    /// <summary>Withdrawal from L2 to L1</summary>
    Withdraw
}

/// <summary>Rollup state</summary>
public enum RollupState { Active, Paused, Finalizing, Finalized }

/// <summary>Proof status</summary>
public enum ProofStatus { Generating, Completed, Failed, Verified }

/// <summary>Zero-knowledge proof</summary>
public record Proof(
    string Id,
    ProofSystem System,
    CircuitType CircuitType,
    string Data,
    List<string> PublicInputs,
    int Size,
    long GenerationTimeMs,
    long CreatedAt
);

/// <summary>Verification key for a circuit</summary>
public record VerificationKey(
    string CircuitId,
    CircuitType CircuitType,
    ProofSystem System,
    string Data,
    int Size
);

/// <summary>Proving key for generating proofs</summary>
public record ProvingKey(
    string CircuitId,
    CircuitType CircuitType,
    ProofSystem System,
    string Data,
    int Size
);

/// <summary>Circuit configuration</summary>
public record CircuitConfig(
    CircuitType Type,
    int? MaxBatchSize = null,
    int? TreeDepth = null,
    bool? VerifySignatures = null,
    Dictionary<string, object>? CustomConstraints = null
);

/// <summary>Account state in the rollup</summary>
public record AccountState(
    string Address,
    string Balance,
    long Nonce,
    string PubkeyHash
);

/// <summary>Transfer operation</summary>
public record Transfer(
    string From,
    string To,
    string Amount,
    string Fee,
    long Nonce,
    string? Signature = null
);

/// <summary>Deposit operation (L1 -> L2)</summary>
public record Deposit(
    string L1TxHash,
    string Recipient,
    string Amount,
    string? Token = null
);

/// <summary>Withdrawal operation (L2 -> L1)</summary>
public record Withdrawal(
    string Sender,
    string Recipient,
    string Amount,
    string? Token,
    long Nonce,
    string? Signature = null
);

/// <summary>Rollup batch</summary>
public record Batch(
    long BatchNumber,
    string PrevStateRoot,
    string NewStateRoot,
    List<Transfer> Transfers,
    List<Deposit> Deposits,
    List<Withdrawal> Withdrawals,
    Proof? Proof,
    long Timestamp
);

/// <summary>Rollup statistics</summary>
public record RollupStats(
    long CurrentBatch,
    long TotalTransactions,
    long TotalProofs,
    long AvgProofTimeMs,
    string StateRoot,
    long AccountCount,
    string Tvl
);

/// <summary>Proof request</summary>
public record ProofRequest(
    CircuitType CircuitType,
    List<string> PublicInputs,
    List<string> PrivateInputs,
    ProofSystem? System = null
);

/// <summary>Verification result</summary>
public record VerificationResult(
    bool Valid,
    long VerificationTimeMs,
    string? Error = null
);

/// <summary>Merkle proof for state inclusion</summary>
public record MerkleProof(
    string Leaf,
    List<string> Path,
    List<int> Indices,
    string Root
);

/// <summary>Ceremony contribution</summary>
public record CeremonyContribution(
    string ContributorId,
    string Hash,
    long Timestamp,
    bool Verified
);

/// <summary>Trusted setup ceremony</summary>
public record TrustedSetup(
    string Id,
    CircuitType CircuitType,
    ProofSystem System,
    int ContributionCount,
    string LatestHash,
    bool Complete,
    List<CeremonyContribution> Contributions
);

/// <summary>ZK SDK configuration</summary>
public record ZkConfig(
    string ApiKey,
    string Endpoint = "https://zk.synor.io/v1",
    string WsEndpoint = "wss://zk.synor.io/v1/ws",
    int Timeout = 60000,
    int Retries = 3,
    ProofSystem DefaultProofSystem = ProofSystem.Groth16,
    bool Debug = false
);

/// <summary>ZK SDK exception</summary>
public class ZkException : Exception
{
    public string? Code { get; }
    public int? Status { get; }

    public ZkException(string message, string? code = null, int? status = null)
        : base(message)
    {
        Code = code;
        Status = status;
    }
}

/// <summary>Proof system characteristics</summary>
public record ProofSystemInfo(
    string Name,
    int ProofSize,
    int VerificationTimeMs,
    bool TrustedSetup,
    bool Universal
);

/// <summary>Extension methods</summary>
public static class ZkExtensions
{
    public static string ToApiString(this ProofSystem system) => system switch
    {
        ProofSystem.Groth16 => "groth16",
        ProofSystem.Plonk => "plonk",
        ProofSystem.Stark => "stark",
        _ => "groth16"
    };

    public static string ToApiString(this CircuitType type) => type switch
    {
        CircuitType.Transfer => "transfer",
        CircuitType.Batch => "batch",
        CircuitType.Deposit => "deposit",
        CircuitType.Withdraw => "withdraw",
        _ => "transfer"
    };

    public static ProofSystemInfo GetInfo(this ProofSystem system) => system switch
    {
        ProofSystem.Groth16 => new ProofSystemInfo("Groth16", 192, 10, true, false),
        ProofSystem.Plonk => new ProofSystemInfo("PLONK", 512, 15, true, true),
        ProofSystem.Stark => new ProofSystemInfo("STARK", 50000, 30, false, true),
        _ => throw new ArgumentOutOfRangeException(nameof(system))
    };
}

/// <summary>Constants</summary>
public static class ZkConstants
{
    public const int MaxBatchSize = 1000;
    public const int StateTreeDepth = 32;
    public const int ProofExpiryBlocks = 100;
}
