use {
    super::{AccountState, Initializable},
    crate::state::SizeOf,
    bytemuck::{Pod, Zeroable},
    pinocchio::pubkey::Pubkey,
    shank::ShankAccount,
};

// Authority field offsets
/// Offset of the authority field in the account data
pub const AUTHORITY_OFFSET: usize = 0;
/// Offset of the pending_authority field in the account data
pub const PENDING_AUTHORITY_OFFSET: usize = 32;

// Parameter field offsets
/// Offset of the inflation_rate field in the account data
pub const INFLATION_RATE_OFFSET: usize = 64;
/// Offset of the lamports_per_signature field in the account data
pub const LAMPORTS_PER_SIGNATURE_OFFSET: usize = 72;
/// Offset of the burn_percent field in the account data
pub const BURN_PERCENT_OFFSET: usize = 80;

// State field offset
/// Offset of the state field in the account data
pub const STATE_OFFSET: usize = 81;

#[repr(C)]
#[derive(ShankAccount, Copy, Clone, Pod, Zeroable)]
pub struct MonetaryPolicyAccount {
    /// Authority that controls monetary policy parameters
    pub authority: Pubkey,
    /// Pending authority for two-step transfer (Pubkey::default() as sentinel)
    pub pending_authority: Pubkey,

    /// Annual inflation rate in basis points (bips): 1 bip = 0.01%, range 0-2000 (0-20%)
    pub inflation_rate_bips: u64,
    /// Target transaction fee in lamports per signature
    pub lamports_per_signature: u64,
    /// Percentage of fees to burn (0-100)
    pub burn_percent: u8,

    /// Account initialization state
    pub state: u8,

    /// Explicit padding to ensure struct is multiple of 8 bytes (required for Pod)
    _padding: [u8; 6],
}

impl MonetaryPolicyAccount {
    #[inline(always)]
    pub fn pack(&self) -> [u8; Self::SIZE_OF] {
        let bytes = bytemuck::bytes_of(self);
        let mut array = [0u8; Self::SIZE_OF];
        array.copy_from_slice(bytes);
        array
    }

    #[inline(always)]
    pub fn set_pending_authority(&mut self, new_pending_authority: &Pubkey) {
        self.pending_authority = *new_pending_authority;
    }

    #[inline(always)]
    pub fn clear_pending_authority(&mut self) {
        self.pending_authority = Pubkey::default();
    }

    #[inline(always)]
    pub fn pending_authority(&self) -> Option<&Pubkey> {
        if self.pending_authority == Pubkey::default() {
            None
        } else {
            Some(&self.pending_authority)
        }
    }

    // Inflation rate methods
    #[inline(always)]
    pub fn inflation_rate_bips(&self) -> u64 {
        self.inflation_rate_bips
    }

    #[inline(always)]
    pub fn set_inflation_rate_bips(&mut self, new_rate_bips: u64) {
        self.inflation_rate_bips = new_rate_bips;
    }

    // Lamports per signature methods
    #[inline(always)]
    pub fn lamports_per_signature(&self) -> u64 {
        self.lamports_per_signature
    }

    #[inline(always)]
    pub fn set_lamports_per_signature(&mut self, new_lamports_per_signature: u64) {
        self.lamports_per_signature = new_lamports_per_signature;
    }

    // Burn percent methods
    #[inline(always)]
    pub fn burn_percent(&self) -> u8 {
        self.burn_percent
    }

    #[inline(always)]
    pub fn set_burn_percent(&mut self, new_percent: u8) {
        self.burn_percent = new_percent;
    }

    #[inline(always)]
    pub fn set_initialized(&mut self) {
        self.state = AccountState::Initialized as u8;
    }
}

impl Initializable for MonetaryPolicyAccount {
    #[inline(always)]
    fn is_initialized(&self) -> bool {
        self.state != AccountState::Uninitialized as u8
    }
}
