// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Error handling for the Rialo SDK.
//!
//! This module defines the common error types used throughout the Rialo SDK
//! and CLI. It provides a centralized error handling mechanism using the
//! thiserror crate for easy error definition and context.

#[cfg(feature = "bincode")]
use rialo_s_sdk::{hash::ParseHashError, pubkey::ParsePubkeyError};
use thiserror::Error;

/// Structured RPC error information parsed from JSON-RPC error responses.
#[derive(Debug, Clone)]
pub struct RpcErrorDetails {
    /// HTTP status code (e.g., 200, 422, 500)
    pub status: Option<u16>,
    /// JSON-RPC error code (e.g., -32002)
    pub code: i64,
    /// Human-readable error message
    pub message: String,
}

impl RpcErrorDetails {
    /// Creates a new RpcErrorDetails with the provided information.
    pub fn new(status: Option<u16>, code: i64, message: String) -> Self {
        Self {
            status,
            code,
            message,
        }
    }

    /// Creates a simple RpcErrorDetails from just a message (for backwards compatibility).
    pub fn from_message(message: String) -> Self {
        Self {
            status: None,
            code: 0,
            message,
        }
    }
}

impl std::fmt::Display for RpcErrorDetails {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // Display just the message for clean user-facing output.
        // HTTP status and error code are available via the struct fields for debugging.
        write!(f, "{}", self.message)
    }
}

/// Represents all possible errors that can occur in the Rialo SDK.
///
/// This enum encompasses errors from various subsystems including IO operations,
/// RPC communication, wallet management, configuration handling, transaction
/// processing, network operations, password management, encryption, and JSON
/// serialization/deserialization.
#[derive(Error, Debug)]
pub enum RialoError {
    /// Errors related to file or system I/O operations.
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    /// Errors occurring during RPC communication with blockchain nodes.
    #[error("RPC error: {0}")]
    Rpc(RpcErrorDetails),

    #[cfg(feature = "bincode")]
    #[error("Pubkey error: {0}")]
    ParsePubkey(#[from] ParsePubkeyError),

    #[cfg(feature = "bincode")]
    #[error("Invalid blockhash format: {0}")]
    InvalidBlockhashFormat(#[from] ParseHashError),

    #[cfg(not(feature = "bincode"))]
    #[error("Pubkey error: {0}")]
    ParsePubkeyError(String),

    #[cfg(not(feature = "bincode"))]
    #[error("Invalid blockhash format: {0}")]
    InvalidBlockhashFormatError(String),

    /// Errors related to keyring operations such as creation, loading, or signing.
    #[error("Keyring error: {0}")]
    Keyring(String),

    /// Errors related to wallet operations such as creation, loading, or signing.
    ///
    /// # Deprecated
    ///
    /// Use `Keyring` variant instead.
    #[deprecated(since = "0.2.0", note = "Use Keyring variant instead")]
    #[error("Wallet error: {0}")]
    Wallet(String),

    /// Errors related to configuration loading, parsing, or validation.
    #[error("Config error: {0}")]
    Config(String),

    /// Errors occurring during transaction building, signing, or submission.
    #[error("Transaction error: {0}")]
    Transaction(String),

    /// Network-related errors, including HTTP client errors.
    #[cfg(feature = "rpc-client")]
    #[error("Network error: {0}")]
    Network(#[from] reqwest::Error),

    /// Errors related to password handling, validation, or verification.
    #[error("Password error: {0}")]
    Password(String),

    /// Errors related to encryption or decryption operations.
    #[error("Encryption error: {0}")]
    Encryption(String),

    /// Errors occurring during JSON parsing, serialization, or deserialization.
    #[error("JSON error: {0}")]
    Json(#[from] serde_json::Error),

    /// Errors related to BIP32 key derivation.
    #[cfg(feature = "hd-wallet")]
    #[error("BIP32 error: {0}")]
    Bip32(#[from] bip32::Error),

    /// Errors related to invalid input parameters or data.
    #[error("Invalid input: {0}")]
    InvalidInput(String),

    /// Errors related to serialization/deserialization.
    #[error("Serialization error: {0}")]
    SerializationError(String),

    /// Transaction confirmation timeout.
    #[error("Transaction confirmation timeout")]
    TransactionTimeout,
}

/// A specialized Result type for Rialo operations.
///
/// This type alias simplifies function signatures and error handling by
/// providing a common Result type that uses RialoError as the error variant.
///
/// # Examples
///
/// ```
/// use rialo_cdk::error::{Result, RialoError};
///
/// fn example_function() -> Result<String> {
///     // Return Ok with a value
///     Ok("Operation succeeded".to_string())
///
///     // Or return an error
///     // Err(RialoError::Config("Missing configuration file".to_string()))
/// }
/// ```
pub type Result<T> = std::result::Result<T, RialoError>;
