use anchor_lang::prelude::*;
use light_utils::fee::compute_rollover_fee;
use crate::{
    state::{queue_from_bytes_zero_copy_init, QueueAccount},
    AccessMetadata, QueueType, RolloverMetadata,
};
pub fn process_initialize_address_queue<'info>(
    queue_account_info: &AccountInfo<'info>,
    queue_loader: &AccountLoader<'info, QueueAccount>,
    index: u64,
    owner: Pubkey,
    program_owner: Option<Pubkey>,
    forester: Option<Pubkey>,
    associated_merkle_tree: Pubkey,
    capacity: u16,
    sequence_threshold: u64,
    network_fee: u64,
    rollover_threshold: Option<u64>,
    close_threshold: Option<u64>,
    height: u32,
    merkle_tree_rent: u64,
) -> Result<()> {
    {
        let mut address_queue = queue_loader.load_init()?;
        let queue_rent = queue_account_info.lamports();
        let rollover_fee = if let Some(rollover_threshold) = rollover_threshold {
            let rollover_fee = compute_rollover_fee(rollover_threshold, height, merkle_tree_rent)
                .map_err(ProgramError::from)?
                + compute_rollover_fee(rollover_threshold, height, queue_rent)
                    .map_err(ProgramError::from)?;
            check_rollover_fee_sufficient(
                rollover_fee,
                queue_rent,
                merkle_tree_rent,
                rollover_threshold,
                height,
            )?;
            msg!("address queue rollover_fee: {}", rollover_fee);
            rollover_fee
        } else {
            0
        };
        address_queue.init(
            AccessMetadata::new(owner, program_owner, forester),
            RolloverMetadata::new(
                index,
                rollover_fee,
                rollover_threshold,
                network_fee,
                close_threshold,
                None,
            ),
            associated_merkle_tree,
            QueueType::AddressQueue,
        );
        drop(address_queue);
    }
    unsafe {
        queue_from_bytes_zero_copy_init(
            &mut queue_account_info.try_borrow_mut_data()?,
            capacity as usize,
            sequence_threshold as usize,
        )
        .map_err(ProgramError::from)?;
    }
    Ok(())
}
pub fn check_rollover_fee_sufficient(
    rollover_fee: u64,
    queue_rent: u64,
    merkle_tree_rent: u64,
    rollover_threshold: u64,
    height: u32,
) -> Result<()> {
    if rollover_fee != queue_rent + merkle_tree_rent
        && (rollover_fee * rollover_threshold * (2u64.pow(height))) / 100
            < queue_rent + merkle_tree_rent
    {
        msg!("rollover_fee: {}", rollover_fee);
        msg!("rollover_threshold: {}", rollover_threshold);
        msg!("height: {}", height);
        msg!("merkle_tree_rent: {}", merkle_tree_rent);
        msg!("queue_rent: {}", queue_rent);
        msg!(
            "((rollover_fee * rollover_threshold * (2u64.pow(height))) / 100): {} < {} rent",
            ((rollover_fee * rollover_threshold * (2u64.pow(height))) / 100),
            queue_rent + merkle_tree_rent
        );
        return err!(crate::errors::AccountCompressionErrorCode::InsufficientRolloverFee);
    }
    Ok(())
}