using System.Text.Json.Serialization;

namespace Synor.Sdk.Wallet;

/// <summary>
/// Network environment for wallet operations.
/// </summary>
public enum Network
{
    [JsonPropertyName("mainnet")] Mainnet,
    [JsonPropertyName("testnet")] Testnet,
    [JsonPropertyName("devnet")] Devnet
}

/// <summary>
/// Type of wallet to create.
/// </summary>
public enum WalletType
{
    [JsonPropertyName("standard")] Standard,
    [JsonPropertyName("multisig")] Multisig,
    [JsonPropertyName("hardware")] Hardware,
    [JsonPropertyName("stealth")] Stealth
}

/// <summary>
/// Transaction priority for fee estimation.
/// </summary>
public enum Priority
{
    [JsonPropertyName("low")] Low,
    [JsonPropertyName("medium")] Medium,
    [JsonPropertyName("high")] High
}

/// <summary>
/// Configuration for the wallet client.
/// </summary>
public class WalletConfig
{
    public required string ApiKey { get; init; }
    public string Endpoint { get; init; } = "https://wallet.synor.io/v1";
    public Network Network { get; init; } = Network.Mainnet;
    public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(30);
    public int Retries { get; init; } = 3;
    public bool Debug { get; init; } = false;
}

/// <summary>
/// A wallet address.
/// </summary>
public record Address(
    [property: JsonPropertyName("address")] string AddressString,
    [property: JsonPropertyName("index")] int Index,
    [property: JsonPropertyName("is_change")] bool IsChange = false
);

/// <summary>
/// A Synor wallet with addresses and keys.
/// </summary>
public record Wallet(
    [property: JsonPropertyName("id")] string Id,
    [property: JsonPropertyName("type")] WalletType Type,
    [property: JsonPropertyName("network")] Network Network,
    [property: JsonPropertyName("addresses")] List<Address> Addresses,
    [property: JsonPropertyName("created_at")] string CreatedAt
);

/// <summary>
/// Stealth address for privacy transactions.
/// </summary>
public record StealthAddress(
    [property: JsonPropertyName("spend_public_key")] string SpendPublicKey,
    [property: JsonPropertyName("view_public_key")] string ViewPublicKey,
    [property: JsonPropertyName("one_time_address")] string OneTimeAddress
);

/// <summary>
/// Result of wallet creation.
/// </summary>
public record CreateWalletResult(
    [property: JsonPropertyName("wallet")] Wallet Wallet,
    [property: JsonPropertyName("mnemonic")] string? Mnemonic = null
);

/// <summary>
/// Transaction input (UTXO reference).
/// </summary>
public record TransactionInput(
    [property: JsonPropertyName("txid")] string Txid,
    [property: JsonPropertyName("vout")] int Vout,
    [property: JsonPropertyName("amount")] long Amount
);

/// <summary>
/// Transaction output.
/// </summary>
public record TransactionOutput(
    [property: JsonPropertyName("address")] string Address,
    [property: JsonPropertyName("amount")] long Amount
);

/// <summary>
/// Transaction for signing.
/// </summary>
public record Transaction(
    List<TransactionInput> Inputs,
    List<TransactionOutput> Outputs,
    long? Fee = null,
    Priority Priority = Priority.Medium
);

/// <summary>
/// Signed transaction ready for broadcast.
/// </summary>
public record SignedTransaction(
    [property: JsonPropertyName("txid")] string Txid,
    [property: JsonPropertyName("hex")] string Hex,
    [property: JsonPropertyName("size")] int Size,
    [property: JsonPropertyName("fee")] long Fee
);

/// <summary>
/// Cryptographic signature.
/// </summary>
public record Signature(
    [property: JsonPropertyName("signature")] string SignatureString,
    [property: JsonPropertyName("address")] string Address,
    [property: JsonPropertyName("recovery_id")] int? RecoveryId = null
);

/// <summary>
/// Unspent transaction output.
/// </summary>
public record UTXO(
    [property: JsonPropertyName("txid")] string Txid,
    [property: JsonPropertyName("vout")] int Vout,
    [property: JsonPropertyName("amount")] long Amount,
    [property: JsonPropertyName("address")] string Address,
    [property: JsonPropertyName("confirmations")] int Confirmations,
    [property: JsonPropertyName("script_pubkey")] string? ScriptPubKey = null
);

/// <summary>
/// Wallet balance information.
/// </summary>
public record Balance(
    [property: JsonPropertyName("confirmed")] long Confirmed,
    [property: JsonPropertyName("unconfirmed")] long Unconfirmed,
    [property: JsonPropertyName("total")] long Total
);

/// <summary>
/// Exception thrown by wallet operations.
/// </summary>
public class WalletException : Exception
{
    public string? Code { get; }
    public int? StatusCode { get; }

    public WalletException(string message, string? code = null, int? statusCode = null)
        : base(message)
    {
        Code = code;
        StatusCode = statusCode;
    }
}
