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

//! Types for the `getStakeAccount` RPC method.

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

use super::rpc_response_context::RpcResponseContext;

/// The state of a stake account.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum StakeState {
    /// The stake account has no active delegation and all funds are withdrawable.
    /// This state means either: never activated, or unbonding is complete.
    Inactive,
    /// The stake account is activating (activation_requested >= last_freeze_timestamp).
    /// Transitions to Active when FreezeStakes is called after the activation request.
    Activating,
    /// The stake account is actively delegated.
    Active,
    /// The stake account is deactivating (deactivation_requested >= last_freeze_timestamp).
    /// Transitions to Unbonding when FreezeStakes is called after the deactivation request.
    Deactivating,
    /// The stake has been deactivated (state transition complete) but the unbonding period
    /// has not yet elapsed. Funds are still locked until unbonding completes.
    /// Transitions to Inactive when the unbonding period elapses.
    Unbonding,
}

/// Request for getStakeAccount RPC call
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Validate)]
pub struct GetStakeAccountRequest {
    /// The public key of the stake account (base58-encoded).
    #[validate(length(min = 1, message = "Address cannot be empty"))]
    #[validate(custom(function = crate::validation::validate_pubkey))]
    pub pubkey: String,
}

impl GetStakeAccountRequest {
    pub fn new(pubkey: String) -> Self {
        Self { pubkey }
    }
}

/// The response message for a getStakeAccount request.
#[derive(Serialize, Deserialize, Debug)]
pub struct GetStakeAccountResponse {
    pub context: RpcResponseContext,
    /// The stake account information, or None if not found.
    pub value: Option<StakeAccountInfo>,
}

/// Information about a stake account.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StakeAccountInfo {
    /// The current state of the stake account.
    pub state: StakeState,
    /// Total kelvins in the account.
    pub kelvins: u64,
    /// The amount delegated to the validator (0 when inactive).
    pub delegated_balance: u64,
    /// The undelegated amount (kelvins - delegated_balance when not inactive, otherwise all kelvins).
    pub undelegated_balance: u64,
    /// The Unix timestamp (in milliseconds) when ActivateStake was called, if any.
    /// Activation takes effect at the next FreezeStakes call (epoch boundary).
    pub activation_requested: Option<u64>,
    /// The Unix timestamp (in milliseconds) when DeactivateStake was called, if any.
    /// Deactivation takes effect at the next FreezeStakes call (epoch boundary).
    pub deactivation_requested: Option<u64>,
    /// The validator info account the stake is delegated to, if any (base58-encoded).
    pub validator: Option<String>,
    /// The admin authority (hot wallet) that can perform ActivateStake/DeactivateStake.
    pub admin_authority: String,
    /// The withdraw authority (cold wallet) required for withdrawals.
    pub withdraw_authority: String,
    /// Optional account that receives rewards if they don't compound (base58-encoded).
    pub reward_receiver: Option<String>,
}
