use crate::output::format_duration_secs;
use super::sort::sort_indices;
use super::types::{ AccountQuota, SortStrategy, PreferStrategy };
use super::format::{ prefer_weekly, renewal_secs, next_event_raw };
fn find_first_eligible< F >(
accounts : &[ AccountQuota ],
sorted : &[ usize ],
now_secs : u64,
extra : F,
) -> Option< usize >
where F : Fn( &AccountQuota ) -> bool
{
for &idx in sorted
{
let aq = &accounts[ idx ];
if aq.is_current || aq.is_active { continue; }
if aq.is_occupied_elsewhere { continue; }
let Ok( data ) = &aq.result else { continue; };
if data.five_hour.as_ref().is_some_and( |p| p.utilization >= 85.0 ) { continue; }
if ( aq.expires_at_ms / 1000 ).saturating_sub( now_secs ) == 0 { continue; }
if !extra( aq ) { continue; }
return Some( idx );
}
None
}
pub( crate ) fn find_next_for_strategy(
accounts : &[ AccountQuota ],
strategy : SortStrategy,
prefer : PreferStrategy,
now_secs : u64,
gate_ownership : bool,
) -> Option< usize >
{
match strategy
{
SortStrategy::Name =>
{
let sorted = sort_indices( accounts, SortStrategy::Name, None, prefer, now_secs );
find_first_eligible( accounts, &sorted, now_secs, |aq| prefer_weekly( aq, prefer ) > 5.0 && ( !gate_ownership || aq.is_owned ) )
}
SortStrategy::Renew =>
{
let sorted = sort_indices( accounts, SortStrategy::Renew, None, prefer, now_secs );
find_first_eligible( accounts, &sorted, now_secs, |aq| prefer_weekly( aq, prefer ) > 5.0 && ( !gate_ownership || aq.is_owned ) )
}
SortStrategy::Renews =>
{
let sorted = sort_indices( accounts, SortStrategy::Renews, None, prefer, now_secs );
find_first_eligible( accounts, &sorted, now_secs, |aq| prefer_weekly( aq, prefer ) > 5.0 && ( !gate_ownership || aq.is_owned ) )
}
}
}
pub( crate ) fn strategy_metric(
aq : &AccountQuota,
strategy : SortStrategy,
_prefer : PreferStrategy,
now_secs : u64,
) -> String
{
match strategy
{
SortStrategy::Name => String::new(),
SortStrategy::Renew =>
{
let Ok( data ) = &aq.result else { return String::new(); };
let d7_secs = data.seven_day.as_ref()
.and_then( |p| p.resets_at.as_deref() )
.and_then( claude_quota::iso_to_unix_secs )
.map( |t| t.saturating_sub( now_secs ) );
let sub_pair = renewal_secs(
aq.renewal_at.as_deref(),
aq.account.as_ref().map( |a| a.org_created_at.as_str() ),
now_secs,
);
let ( sub_s, sub_est ) = match sub_pair
{
Some( ( s, est ) ) => ( Some( s ), est ),
None => ( None, false ),
};
match next_event_raw( d7_secs, sub_s, sub_est )
{
None => "\u{2014}".to_string(),
Some( ( secs, prefix, true ) ) => format!( "~in {} {prefix}", format_duration_secs( secs ) ),
Some( ( secs, prefix, false ) ) => format!( "in {} {prefix}", format_duration_secs( secs ) ),
}
}
SortStrategy::Renews =>
{
let sub_pair = renewal_secs(
aq.renewal_at.as_deref(),
aq.account.as_ref().map( |a| a.org_created_at.as_str() ),
now_secs,
);
match sub_pair
{
Some( ( s, false ) ) => format!( "renews in {}", format_duration_secs( s ) ),
Some( ( s, true ) ) => format!( "~renews in {}", format_duration_secs( s ) ),
None => String::new(),
}
}
}
}
#[ cfg( test ) ]
#[ path = "sort_next_tests.rs" ]
mod tests;