mod basic;
mod core;
mod full;
mod minimal;

pub use self::core::UnrealizedCore;
pub use basic::UnrealizedBasic;
pub use full::UnrealizedFull;
pub use minimal::UnrealizedMinimal;

use brk_error::Result;
use brk_indexer::Lengths;
use brk_types::{Height, Sats};
use vecdb::{Exit, ReadableVec};

use crate::{distribution::state::UnrealizedState, price};

pub trait UnrealizedLike: Send + Sync {
    fn as_core(&self) -> &UnrealizedCore;
    fn as_core_mut(&mut self) -> &mut UnrealizedCore;
    fn min_stateful_len(&self) -> usize;
    fn push_state(&mut self, state: &UnrealizedState);
    fn compute_rest(
        &mut self,
        prices: &price::Vecs,
        starting_lengths: &Lengths,
        supply_in_profit_sats: &(impl ReadableVec<Height, Sats> + Sync),
        supply_in_loss_sats: &(impl ReadableVec<Height, Sats> + Sync),
        exit: &Exit,
    ) -> Result<()>;
}

impl UnrealizedLike for UnrealizedCore {
    fn as_core(&self) -> &UnrealizedCore {
        self
    }
    fn as_core_mut(&mut self) -> &mut UnrealizedCore {
        self
    }
    fn min_stateful_len(&self) -> usize {
        self.min_stateful_len()
    }
    #[inline(always)]
    fn push_state(&mut self, state: &UnrealizedState) {
        self.push_state(state);
    }
    fn compute_rest(
        &mut self,
        _prices: &price::Vecs,
        starting_lengths: &Lengths,
        _supply_in_profit_sats: &(impl ReadableVec<Height, Sats> + Sync),
        _supply_in_loss_sats: &(impl ReadableVec<Height, Sats> + Sync),
        exit: &Exit,
    ) -> Result<()> {
        self.compute_rest(starting_lengths, exit)
    }
}

impl UnrealizedLike for UnrealizedFull {
    fn as_core(&self) -> &UnrealizedCore {
        &self.inner
    }
    fn as_core_mut(&mut self) -> &mut UnrealizedCore {
        &mut self.inner
    }
    fn min_stateful_len(&self) -> usize {
        UnrealizedFull::min_stateful_len(self)
    }
    #[inline(always)]
    fn push_state(&mut self, state: &UnrealizedState) {
        self.push_state_all(state);
    }
    fn compute_rest(
        &mut self,
        prices: &price::Vecs,
        starting_lengths: &Lengths,
        supply_in_profit_sats: &(impl ReadableVec<Height, Sats> + Sync),
        supply_in_loss_sats: &(impl ReadableVec<Height, Sats> + Sync),
        exit: &Exit,
    ) -> Result<()> {
        self.compute_rest_all(
            prices,
            starting_lengths,
            supply_in_profit_sats,
            supply_in_loss_sats,
            exit,
        )
    }
}
