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

use rialo_shared_types::AccountInfoResponseValue;
use serde::{Deserialize, Serialize};
use validator::Validate;

use super::rpc_response_context::RpcResponseContext;

/// Encoding configuration used for account/transaction data
///
/// This configuration determines how account data is encoded in the response.
///
/// ## Supported Encodings
/// - `base64` - Data encoded as base64 string
/// - `base58` - Data encoded as base58 string  
/// - `json` - Data parsed as JSON (for known program accounts)
/// - `jsonParsed` - Data parsed as JSON with additional metadata
///
/// ## Example
/// ```rust
/// use rialo_api_types::messages::get_account_info::EncodingConfig;
///
/// // Base64 encoding configuration
/// let config = EncodingConfig::new("base64".to_string());
///
/// // Pre-built configurations
/// let base64_config = EncodingConfig::base64();
/// let json_config = EncodingConfig::json();
/// ```
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EncodingConfig {
    /// Data encoding format (base64, base58, json, jsonParsed)
    pub encoding: String,
}

impl EncodingConfig {
    pub fn new(encoding: String) -> Self {
        Self { encoding }
    }

    pub fn base64() -> Self {
        Self {
            encoding: "base64".to_string(),
        }
    }

    pub fn json() -> Self {
        Self {
            encoding: "json".to_string(),
        }
    }
}

/// Request parameters for the `getAccountInfo` RPC method
///
/// Gets account information for a given public key. Returns detailed information
/// about the account including lamport balance, data, owner program, and executable status.
///
/// Solana specification: <https://solana.com/docs/rpc/http/getaccountinfo>
///
/// ## JSON-RPC Request Format
/// ```json
/// {
///   "jsonrpc": "2.0",
///   "id": 1,
///   "method": "getAccountInfo",
///   "params": [
///     "7xB9i2AcjLNJ6M8iZ3LZJvLm7xpSmH7T5uZzR3DeVXWi",
///     {
///       "encoding": "base64",
///     }
///   ]
/// }
/// ```
///
/// ## Example Response
/// ```json
/// {
///   "jsonrpc": "2.0",
///   "id": 1,
///   "result": {
///     "context": {
///       "slot": 1234567
///     },
///     "value": {
///       "data": ["SGVsbG8gV29ybGQ=", "base64"],
///       "executable": false,
///       "lamports": 1000000000,
///       "owner": "11111111111111111111111111111111",
///       "rentEpoch": 200
///     }
///   }
/// }
/// ```
///
/// ## Usage Example
/// ```rust
/// use rialo_api_types::messages::get_account_info::{GetAccountInfoRequest, GetAccountInfoConfig};
///
/// let request = GetAccountInfoRequest {
///     address: "7xB9i2AcjLNJ6M8iZ3LZJvLm7xpSmH7T5uZzR3DeVXWi".to_string(),
///     config: Some(GetAccountInfoConfig {
///         encoding: Some("base64".to_string()),
///         data_slice: None,
///         min_context_slot: None,
///     })
/// };
/// ```
#[derive(Debug, Serialize, Deserialize, PartialEq, Validate)]
pub struct GetAccountInfoRequest {
    /// The account public key to query (base58-encoded)
    #[validate(length(min = 1, message = "Address cannot be empty"))]
    #[validate(custom(function = crate::validation::validate_pubkey))]
    pub address: String,
    /// Optional configuration for encoding and data slicing
    pub config: Option<GetAccountInfoConfig>,
}

/// Config parameters for the getAccountInfo request.
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct GetAccountInfoConfig {
    pub encoding: Option<String>,
    #[serde(rename = "dataSlice")]
    pub data_slice: Option<DataSliceConfig>,
    #[serde(rename = "minContextSlot")]
    pub min_context_slot: Option<String>,
}

/// Config parameters for how much data should be returned.
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct DataSliceConfig {
    pub offset: u64,
    pub length: u64,
}

/// The response message for a getAccountInfo request.
/// Solana specification: <https://solana.com/docs/rpc/http/getaccountinfo>
#[derive(Serialize, Deserialize, Debug)]
pub struct AccountInfoResponse {
    pub context: RpcResponseContext,
    pub value: Option<AccountInfoResponseValue>,
}
