use brk_types::{Age, Height};
use rustc_hash::FxHashMap;
use vecdb::{Rw, VecIndex};
use crate::distribution::{
compute::PriceRangeMax,
state::{BlockState, SendPrecomputed, Transacted},
};
use super::groups::UTXOCohorts;
impl UTXOCohorts<Rw> {
pub(crate) fn send(
&mut self,
height_to_sent: FxHashMap<Height, Transacted>,
chain_state: &mut [BlockState],
price_range_max: &PriceRangeMax,
) -> Option<Height> {
if chain_state.is_empty() {
return None;
}
let last_block = chain_state.last().unwrap();
let last_timestamp = last_block.timestamp;
let current_price = last_block.price;
let chain_len = chain_state.len();
let send_height = Height::from(chain_len - 1);
let mut min_receive_height: Option<Height> = None;
for (receive_height, sent) in height_to_sent {
min_receive_height =
Some(min_receive_height.map_or(receive_height, |cur| cur.min(receive_height)));
chain_state[receive_height.to_usize()].supply -= &sent.spendable_supply;
let block_state = &chain_state[receive_height.to_usize()];
let prev_price = block_state.price;
let age = Age::new(last_timestamp, block_state.timestamp);
let peak_price = price_range_max.max_between(receive_height, send_height);
if let Some(pre) = SendPrecomputed::new(
&sent.spendable_supply,
current_price,
prev_price,
peak_price,
age,
) {
self.age_range
.get_mut(age)
.state
.as_mut()
.unwrap()
.send_utxo_precomputed(&sent.spendable_supply, &pre);
if let Some(v) = self.epoch.mut_vec_from_height(receive_height) {
v.state
.as_mut()
.unwrap()
.send_utxo_precomputed(&sent.spendable_supply, &pre);
}
if let Some(v) = self.class.mut_vec_from_timestamp(block_state.timestamp) {
v.state
.as_mut()
.unwrap()
.send_utxo_precomputed(&sent.spendable_supply, &pre);
}
} else if sent.spendable_supply.utxo_count > 0 {
self.age_range.get_mut(age).state.as_mut().unwrap().supply -=
&sent.spendable_supply;
if let Some(v) = self.epoch.mut_vec_from_height(receive_height) {
v.state.as_mut().unwrap().supply -= &sent.spendable_supply;
}
if let Some(v) = self.class.mut_vec_from_timestamp(block_state.timestamp) {
v.state.as_mut().unwrap().supply -= &sent.spendable_supply;
}
}
sent.by_type
.spendable
.iter_typed()
.filter(|(_, supply_state)| supply_state.utxo_count > 0)
.for_each(|(output_type, supply_state)| {
self.type_
.get_mut(output_type)
.state
.as_mut()
.unwrap()
.send_utxo(supply_state, current_price, prev_price, peak_price, age)
});
sent.by_size_group
.iter_typed()
.filter(|(_, supply_state)| supply_state.utxo_count > 0)
.for_each(|(group, supply_state)| {
self.amount_range
.get_mut(group)
.state
.as_mut()
.unwrap()
.send_utxo(supply_state, current_price, prev_price, peak_price, age);
});
}
min_receive_height
}
}