use std::time::Duration;

use alloy::primitives::{B256, U256};
use proposer::{config::ProposerConfigs, proposer::Proposer};
use serial_test::serial;
use test_context::test_context;
use test_harness::{ShastaEnv, mine_l1_block, shasta::get_proposal_hash};

fn base_proposer_config(env: &ShastaEnv) -> ProposerConfigs {
    ProposerConfigs {
        client: env.client_config.clone(),
        l2_suggested_fee_recipient: env.l2_suggested_fee_recipient,
        propose_interval: Duration::from_secs(0),
        l1_proposer_private_key: env.l1_proposer_private_key,
        gas_limit: None,
        use_engine_mode: false,
        retry_interval: Duration::from_secs(48),
        confirmation_timeout: Duration::from_secs(180),
        receipt_query_interval: Some(Duration::from_millis(100)),
        min_tip_cap_gwei: 1,
        min_base_fee_gwei: 1,
        min_blob_fee_gwei: 1,
    }
}

#[test_context(ShastaEnv)]
#[serial]
#[test_log::test(tokio::test)]
async fn propose_shasta_batches(env: &mut ShastaEnv) -> anyhow::Result<()> {
    let proposer_config = base_proposer_config(env);

    let proposer = Proposer::new(proposer_config).await?;
    let provider = proposer.rpc_client();

    for i in 0..3 {
        assert_eq!(B256::ZERO, get_proposal_hash(&provider, U256::from(i + 1)).await?);

        mine_l1_block(&provider).await?;
        assert!(proposer.fetch_and_propose().await?.status());

        assert_ne!(B256::ZERO, get_proposal_hash(&provider, U256::from(i + 1)).await?);
    }

    Ok(())
}

/// Test that engine mode can successfully propose batches using the FCU + get_payload flow.
#[test_context(ShastaEnv)]
#[serial]
#[test_log::test(tokio::test)]
async fn propose_shasta_batches_engine_mode(env: &mut ShastaEnv) -> anyhow::Result<()> {
    let mut proposer_config = base_proposer_config(env);
    proposer_config.use_engine_mode = true;

    let proposer = Proposer::new(proposer_config).await?;
    let provider = proposer.rpc_client();

    for i in 0..3 {
        assert_eq!(B256::ZERO, get_proposal_hash(&provider, U256::from(i + 1)).await?);

        mine_l1_block(&provider).await?;
        assert!(proposer.fetch_and_propose().await?.status());

        assert_ne!(B256::ZERO, get_proposal_hash(&provider, U256::from(i + 1)).await?);
    }

    Ok(())
}
