use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::{
    storage,
    traits::{Get, UncheckedOnRuntimeUpgrade},
    weights::Weight,
};
use ghost_networks::NetworkDataInspectHandler;
use scale_info::TypeInfo;
use sp_runtime::traits::{BlockNumberProvider, UniqueSaturatedInto};
use sp_runtime::RuntimeDebug;
use sp_std::marker::PhantomData;

use crate::{AuthIndex, BTreeMap, BlockCommitments, CommitmentDetails, Config, Pallet, LOG_TARGET};

#[derive(
    RuntimeDebug,
    Default,
    Copy,
    Clone,
    Eq,
    PartialEq,
    Ord,
    PartialOrd,
    Encode,
    Decode,
    TypeInfo,
    MaxEncodedLen,
)]
pub struct OldCommitmentDetails {
    pub last_stored_block: u64,
    pub last_updated: u64,
    pub commits: u64,
}

pub struct CommitmentDetailsTypesChanged<T>(PhantomData<T>);
impl<T: Config> UncheckedOnRuntimeUpgrade for CommitmentDetailsTypesChanged<T> {
    fn on_runtime_upgrade() -> Weight {
        let mut weight = T::DbWeight::get().reads(3);
        let current_block_number = <Pallet<T> as BlockNumberProvider>::current_block_number();

        for network_id in T::NetworkDataHandler::iter_indexes() {
            let mut new_btree_map = BTreeMap::new();

            let key_hash = BlockCommitments::<T>::hashed_key_for(&network_id);
            let old_commitments = storage::unhashed::take_or_default::<
                BTreeMap<AuthIndex, OldCommitmentDetails>,
            >(&key_hash);

            for (authority_index, details) in old_commitments.iter() {
                new_btree_map.insert(
                    authority_index,
                    CommitmentDetails {
                        last_stored_block: details.last_stored_block,
                        last_updated: current_block_number,
                        commits: details.commits.unique_saturated_into(),
                    },
                );
            }
            BlockCommitments::<T>::insert(&network_id, new_btree_map);
            weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));

            log::info!(
                target: LOG_TARGET,
                "👻 Block commitments migrated from unix timestamp to internal block for network {:?}",
                network_id,
            );
        }

        weight
    }
}
