use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight};
use sp_runtime::{create_runtime_str, Perbill};
use sp_version::RuntimeVersion;

use crate::types::BlockNumber;

pub mod currency {
    use crate::types::Balance;

    pub const MICROCENTS: Balance = 1_000_000;
    pub const MILLICENTS: Balance = 1_000_000_000;
    pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent.
    pub const DOLLARS: Balance = 100 * CENTS;
    pub const GRAND: Balance = 1_000 * DOLLARS;

    /// NB: Notice, that existential deposit was set to 0 intentionally to increase compatibility with EVM.
    /// However, it leads to some risks, most importantly state bloating.
    /// We acknowledge that there is such a risk and we have an opened issue to resolve it:
    /// https://github.com/OpenZeppelin/polkadot-runtime-templates/issues/195
    /// If you read this message please check out this issue to see if it is resolved and what can you do to implement the fix.
    #[cfg(not(feature = "runtime-benchmarks"))]
    pub const EXISTENTIAL_DEPOSIT: Balance = 0;

    #[cfg(feature = "runtime-benchmarks")]
    pub const EXISTENTIAL_DEPOSIT: Balance = 1;

    pub const fn deposit(items: u32, bytes: u32) -> Balance {
        items as Balance * 15 * CENTS + (bytes as Balance) * 6 * CENTS
    }
}

pub const P_FACTOR: u128 = 10;
pub const Q_FACTOR: u128 = 100;
pub const POLY_DEGREE: u8 = 1;

#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
    spec_name: create_runtime_str!("template-parachain"),
    impl_name: create_runtime_str!("template-parachain"),
    authoring_version: 1,
    spec_version: 1,
    impl_version: 0,
    apis: crate::RUNTIME_API_VERSIONS,
    transaction_version: 1,
    state_version: 1,
};

/// This determines the average expected block time that we are targeting.
/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`.
/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
/// up by `pallet_aura` to implement `fn slot_duration()`.
///
/// Change this to adjust the block time.
#[cfg(feature = "async-backing")]
pub const MILLISECS_PER_BLOCK: u64 = 6000;
#[cfg(not(feature = "async-backing"))]
pub const MILLISECS_PER_BLOCK: u64 = 12000;

// NOTE: Currently it is not possible to change the slot duration after the
// chain has started. Attempting to do so will brick block production.
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;

// Time is measured by number of blocks.
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;

/// We assume that ~5% of the block weight is consumed by `on_initialize`
/// handlers. This is used to limit the maximal weight of a single extrinsic.
pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5);

/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be
/// used by `Operational` extrinsics.
pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);

pub const WEIGHT_MILLISECS_PER_BLOCK: u64 = 2000;

/// We allow for 0.5 of a second of compute with a 12 second average block time.
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
    #[cfg(feature = "async-backing")]
    WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2),
    #[cfg(not(feature = "async-backing"))]
    WEIGHT_REF_TIME_PER_SECOND.saturating_div(2),
    cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64,
);

/// Maximum number of blocks simultaneously accepted by the Runtime, not yet
/// included into the relay chain.
#[cfg(feature = "async-backing")]
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3;
#[cfg(not(feature = "async-backing"))]
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent.
/// Limits the number of blocks authored per slot.
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
/// Maximum length for a block.
pub const MAX_BLOCK_LENGTH: u32 = 5 * 1024 * 1024;

/// Current approximation of the gas/s consumption considering
/// EVM execution over compiled WASM (on 4.4Ghz CPU).
/// Given the 500ms Weight, from which 75% only are used for transactions,
/// the total EVM execution gas limit is: GAS_PER_SECOND * 0.500 * 0.75 ~= 15_000_000.
/// With the async backing enabled the gas limit will rise 4 times because of execution time.
pub const GAS_PER_SECOND: u64 = 40_000_000;

/// Approximate ratio of the amount of Weight per Gas.
/// u64 works for approximations because Weight is a very small unit compared to gas.
pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND;
