use frame_support::{
    migration::clear_storage_prefix,
    traits::{Get, PalletInfoAccess, UncheckedOnRuntimeUpgrade},
    weights::Weight,
};
use sp_std::marker::PhantomData;

use crate::{BoundedVec, Config, NetworkIndexes, Networks, Pallet, Vec, LOG_TARGET};

pub struct StoreNetworkIdsIntoBoundedVec<T>(PhantomData<T>);
impl<T: Config> UncheckedOnRuntimeUpgrade for StoreNetworkIdsIntoBoundedVec<T> {
    fn on_runtime_upgrade() -> Weight {
        let mut weight = T::DbWeight::get().reads(1);

        let network_ids: Vec<T::NetworkId> = Networks::<T>::iter_keys().collect();
        let networks_count = network_ids.len();

        weight = weight.saturating_add(T::DbWeight::get().reads(networks_count as u64));

        let clear_results = clear_storage_prefix(
            Pallet::<T>::name().as_bytes(),
            "NullifyNeeded".as_bytes(),
            &[],
            Some(1),
            None,
        );
        log::info!(
            target: LOG_TARGET,
            "⛓️  NullifyNeeded storage succesfully removed: Loops (reads): {}, Unique removed (writes): {}",
            clear_results.loops,
            clear_results.unique,
        );

        weight = weight.saturating_add(T::DbWeight::get().reads(clear_results.loops as u64));
        weight = weight.saturating_add(T::DbWeight::get().writes(clear_results.unique as u64));

        let writes = BoundedVec::<T::NetworkId, T::MaxNetworks>::try_from(network_ids)
            .inspect_err(|err| {
                log::error!(
                        target: LOG_TARGET,
                        "⛓️  Network ids to bounded_vec migration failed: {:?}",
                        err,
                )
            })
            .ok()
            .map(|bounded_networks| {
                NetworkIndexes::<T>::put(bounded_networks);
                log::info!(
                    target: LOG_TARGET,
                    "⛓️  Network ids to bounded_vec migration success: {} networks moved",
                    networks_count,
                );
                1u64
            })
            .unwrap_or_default();

        weight.saturating_add(T::DbWeight::get().writes(writes))
    }
}
