use alloy::providers::Provider;
use clap::Parser;
use eyre::Result;
use mevlog::{
    misc::{
        data_fetch::fetch_blocks_batch,
        ens_utils::ENSLookup,
        shared_init::{ConnOpts, OutputFormat, SharedOpts, init_deps},
        symbol_utils::ERC20SymbolsLookup,
        utils::get_native_token_price,
    },
    models::{
        mev_block::{PreFetchedBlockData, generate_block},
        txs_filter::{TxsFilter, TxsFilterOpts},
    },
};

#[derive(Debug, Parser)]
pub struct WatchArgs {
    #[command(flatten)]
    filter_opts: TxsFilterOpts,

    #[command(flatten)]
    shared_opts: SharedOpts,

    #[command(flatten)]
    conn_opts: ConnOpts,
}

impl WatchArgs {
    pub async fn run(&self, format: OutputFormat) -> Result<()> {
        let deps = init_deps(&self.conn_opts).await?;

        let txs_filter = TxsFilter::new(&self.filter_opts, None, &self.shared_opts, true, None)?;

        let ens_query = txs_filter
            .from_ens_query()
            .or_else(|| txs_filter.to_ens_query());

        let ens_lookup = ENSLookup::lookup_mode(
            ens_query,
            deps.ens_lookup_worker,
            &deps.chain,
            self.shared_opts.ens,
            &deps.provider,
        )
        .await?;

        let symbols_lookup = ERC20SymbolsLookup::lookup_mode(
            deps.symbols_lookup_worker,
            self.shared_opts.erc20_symbols,
        );

        let native_token_price = get_native_token_price(
            &deps.chain,
            &deps.provider,
            self.shared_opts.native_token_price,
        )
        .await?;

        let mut current_block_number = deps.provider.get_block_number().await? - 1;

        loop {
            let new_block_number = deps.provider.get_block_number().await?;
            if new_block_number == current_block_number {
                tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
                continue;
            }
            current_block_number = new_block_number;

            let batch_data = fetch_blocks_batch(
                current_block_number,
                current_block_number,
                &deps.chain,
                &deps.sqlite,
                &symbols_lookup,
                txs_filter.show_erc20_transfer_amount,
            )
            .await?;

            let pre_fetched = PreFetchedBlockData {
                txs_data: batch_data
                    .txs_by_block
                    .get(&current_block_number)
                    .cloned()
                    .unwrap_or_default(),
                logs_data: batch_data
                    .logs_by_block
                    .get(&current_block_number)
                    .cloned()
                    .unwrap_or_default(),
            };

            let mev_block = generate_block(
                &deps.provider,
                &deps.sqlite,
                current_block_number,
                &ens_lookup,
                &txs_filter,
                &self.shared_opts,
                &deps.chain,
                &deps.rpc_url,
                native_token_price,
                pre_fetched,
            )
            .await?;

            mev_block.print_with_format(&format);
        }

        #[allow(unreachable_code)]
        Ok(())
    }
}
