use crate::conventions::{Sat, Usd, TRANSITION_DATE};
use crate::event::{BasisSource, LotPick};
use crate::identity::EventId;
use crate::price::PriceProvider;
use crate::project::fold::{fold_event, FoldCtx}; use crate::project::pools::{PoolKey, PoolSet};
use crate::project::resolve::{sort_canonical, Eff, ElectionRec, TransitionMode};
use crate::state::{FoldStats, LedgerState, Lot};
use crate::{LotMethod, ProjectionConfig};
use std::collections::BTreeMap;
pub struct UniversalSnapshot {
pub held_sat: Sat,
pub basis: Usd,
pub estimated_conservative_remaining_sat: Sat,
}
pub fn universal_snapshot(
timeline: &[Eff],
prices: &dyn PriceProvider,
config: &ProjectionConfig,
method: LotMethod,
elections: &[ElectionRec],
selections: &BTreeMap<EventId, Vec<LotPick>>,
promotes: &crate::conservative_promote::PromoteSet,
) -> UniversalSnapshot {
let cfg = ProjectionConfig {
pre2025_method: method,
..*config
}; let mut pre: Vec<Eff> = timeline
.iter()
.filter(|e| e.date() < TRANSITION_DATE)
.cloned()
.collect();
sort_canonical(&mut pre); let mut pools = PoolSet::default();
let mut sink = LedgerState::default(); let mut stats = FoldStats::default();
let ctx = FoldCtx {
config: &cfg,
elections,
selections,
promotes: promotes.clone(),
};
for eff in &pre {
fold_event(eff, prices, &ctx, &mut pools, &mut sink, &mut stats);
}
let lots = pools
.pools
.get(&PoolKey::Universal)
.map(Vec::as_slice)
.unwrap_or(&[]);
UniversalSnapshot {
held_sat: lots.iter().map(|l| l.remaining_sat).sum(),
basis: lots.iter().map(|l| l.usd_basis).sum(),
estimated_conservative_remaining_sat: lots
.iter()
.filter(|l| l.basis_source == BasisSource::EstimatedConservative)
.map(|l| l.remaining_sat)
.sum(),
}
}
pub fn seed_transition(mode: &TransitionMode, pools: &mut PoolSet, _st: &mut LedgerState) {
let universal: Vec<Lot> = pools.pools.remove(&PoolKey::Universal).unwrap_or_default();
match mode {
TransitionMode::PathA => {
for mut lot in universal.into_iter().filter(|l| l.remaining_sat > 0) {
if lot.basis_source != BasisSource::EstimatedConservative {
lot.basis_source = BasisSource::ReconstructedPerWallet;
}
let key = PoolKey::Wallet(lot.wallet.clone());
pools.push_lot(key, lot);
}
}
TransitionMode::PathB { seed } => {
let seed_len = seed.len() as u32;
for lot in seed.iter().cloned() {
let key = PoolKey::Wallet(lot.wallet.clone());
pools.push_lot(key, lot);
}
if let Some(first) = seed.first() {
pools.init_split_counter(&first.lot_id.origin_event_id, seed_len);
}
}
}
}