use crate::{self as ghost_networks};
use frame_support::{
    construct_runtime, ord_parameter_types, parameter_types,
    traits::{ConstU128, ConstU32, Everything},
};
use frame_system::EnsureSignedBy;
pub use primitives::{
    AccountId, Balance, BlockNumber, FreezeIdentifier, Hash, Nonce, ReserveIdentifier,
};
use sp_runtime::{
    curve::PiecewiseLinear,
    traits::{AccountIdLookup, BlakeTwo256},
    BuildStorage,
};

parameter_types! {
    pub const BlockHashCount: BlockNumber = 250;
    pub static SlashDeferDuration: u32 = 0;
    pub static Period: BlockNumber = 5;
    pub static Offset: BlockNumber = 0;
    pub static MaxControllersInDeprecationBatch: u32 = 5_000;
}

impl frame_system::Config for Test {
    type RuntimeEvent = RuntimeEvent;
    type BaseCallFilter = Everything;
    type BlockWeights = ();
    type BlockLength = ();
    type RuntimeOrigin = RuntimeOrigin;
    type RuntimeCall = RuntimeCall;
    type RuntimeTask = ();
    type Nonce = Nonce;
    type Hash = Hash;
    type Hashing = BlakeTwo256;
    type AccountId = AccountId;
    type Lookup = AccountIdLookup<Self::AccountId, ()>;
    type Block = Block;
    type BlockHashCount = BlockHashCount;
    type DbWeight = ();
    type Version = ();
    type PalletInfo = PalletInfo;
    type AccountData = pallet_balances::AccountData<Balance>;
    type OnNewAccount = ();
    type OnKilledAccount = ();
    type SystemWeightInfo = ();
    type SS58Prefix = ();
    type OnSetCode = ();
    type MaxConsumers = ConstU32<16>;
    type SingleBlockMigrations = ();
    type MultiBlockMigrator = ();
    type PreInherents = ();
    type PostInherents = ();
    type PostTransactions = ();
}

impl pallet_balances::Config for Test {
    type RuntimeEvent = RuntimeEvent;
    type RuntimeHoldReason = ();
    type RuntimeFreezeReason = ();
    type WeightInfo = ();
    type Balance = Balance;
    type DustRemoval = ();
    type ExistentialDeposit = ConstU128<1>;
    type AccountStore = System;
    type ReserveIdentifier = ReserveIdentifier;
    type FreezeIdentifier = FreezeIdentifier;
    type MaxLocks = ();
    type MaxReserves = ConstU32<50>;
    type MaxFreezes = ConstU32<50>;
}

pallet_staking_reward_curve::build! {
    const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
        min_inflation: 0_006_900,
        max_inflation: 1_000_000,
        ideal_stake: 0_690_000,
        falloff: 0_050_000,
        max_piece_count: 100,
        test_precision: 0_005_000,
    );
}

parameter_types! {
    pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
    pub const MaxNetworks: u32 = 3;
}

ord_parameter_types! {
    pub const RegistererAccount: AccountId = AccountId::from([1u8; 32]);
    pub const UpdaterAccount: AccountId = AccountId::from([2u8; 32]);
    pub const RemoverAccount: AccountId = AccountId::from([3u8; 32]);
    pub const RandomAccount: AccountId = AccountId::from([4u8; 32]);
}

impl ghost_networks::Config for Test {
    type RuntimeEvent = RuntimeEvent;
    type Currency = Balances;
    type NetworkId = u32;
    type RegisterOrigin = EnsureSignedBy<RegistererAccount, AccountId>;
    type UpdateOrigin = EnsureSignedBy<UpdaterAccount, AccountId>;
    type RemoveOrigin = EnsureSignedBy<RemoverAccount, AccountId>;
    type MaxNetworks = MaxNetworks;
    type WeightInfo = ();
}

type Block = frame_system::mocking::MockBlock<Test>;

construct_runtime!(
    pub enum Test {
        System: frame_system,
        Balances: pallet_balances,
        GhostNetworks: ghost_networks,
    }
);

pub(crate) struct ExtBuilder();
impl ExtBuilder {
    pub(crate) fn build() -> sp_io::TestExternalities {
        let t = frame_system::GenesisConfig::<Test>::default()
            .build_storage()
            .expect("Frame system builds valid default genesis config; qed");

        let mut ext: sp_io::TestExternalities = t.into();
        ext.execute_with(|| System::set_block_number(1));
        ext
    }
}
