use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, PartsPerMillion32, PartsPerMillionSigned32, Version};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};

use crate::internal::{PercentPerBlock, RatioDollars};

use crate::distribution::metrics::{ImportConfig, UnrealizedCore};

/// Extended relative metrics for own total unrealized PnL (extended only).
#[derive(Traversable)]
pub struct RelativeExtendedOwnPnl<M: StorageMode = Rw> {
    #[traversable(wrap = "unrealized/profit", rename = "to_own_gross_pnl")]
    pub unrealized_profit_to_own_gross_pnl: PercentPerBlock<PartsPerMillion32, M>,
    #[traversable(wrap = "unrealized/loss", rename = "to_own_gross_pnl")]
    pub unrealized_loss_to_own_gross_pnl: PercentPerBlock<PartsPerMillion32, M>,
    #[traversable(wrap = "unrealized/net_pnl", rename = "to_own_gross_pnl")]
    pub net_unrealized_pnl_to_own_gross_pnl: PercentPerBlock<PartsPerMillionSigned32, M>,
}

impl RelativeExtendedOwnPnl {
    pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
        Ok(Self {
            unrealized_profit_to_own_gross_pnl: cfg
                .import("unrealized_profit_to_own_gross_pnl", Version::ONE)?,
            unrealized_loss_to_own_gross_pnl: cfg
                .import("unrealized_loss_to_own_gross_pnl", Version::ONE)?,
            net_unrealized_pnl_to_own_gross_pnl: cfg
                .import("net_unrealized_pnl_to_own_gross_pnl", Version::new(3))?,
        })
    }

    pub(crate) fn compute(
        &mut self,
        max_from: Height,
        unrealized: &UnrealizedCore,
        gross_pnl_usd: &impl ReadableVec<Height, Dollars>,
        exit: &Exit,
    ) -> Result<()> {
        self.unrealized_profit_to_own_gross_pnl
            .compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
                max_from,
                &unrealized.profit.usd.height,
                gross_pnl_usd,
                exit,
            )?;
        self.unrealized_loss_to_own_gross_pnl
            .compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
                max_from,
                &unrealized.loss.usd.height,
                gross_pnl_usd,
                exit,
            )?;
        self.net_unrealized_pnl_to_own_gross_pnl
            .compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillionSigned32>>(
                max_from,
                &unrealized.net_pnl.usd.height,
                gross_pnl_usd,
                exit,
            )?;
        Ok(())
    }
}
