use std::str::FromStr;
use chrono::{DateTime, Utc};
use lunar_lib::{error, iterator_ext::IteratorExtensions};
use regex::Regex;
use serde::{Deserialize, Serialize};
use crate::library::{
album::{Album, AlbumId},
artist::ArtistId,
collection::rules::{EqOp, OrdOp, Rule, eq_many, eq_single, ord_single},
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AlbumRule {
Id { ids: Vec<AlbumId>, op: EqOp },
Name { regex: Vec<String>, op: EqOp },
Artists { artists: Vec<ArtistId>, op: EqOp },
Discs { count: u32, op: OrdOp },
Tracks { count: u32, op: OrdOp },
Genre { genres: Vec<String>, op: EqOp },
Date { date: DateTime<Utc>, op: OrdOp },
}
impl Rule for AlbumRule {
type Item = Album;
fn matches(&self, item: &Self::Item) -> bool {
match self {
AlbumRule::Id { ids: id, op } => eq_single(&item.id(), id, *op),
AlbumRule::Name { regex, op } => {
let regex: Vec<_> = match regex.iter().try_map(|r| Regex::from_str(r)) {
Ok(v) => v.collect(),
Err(err) => {
error!("Failed to create regex: {err}");
return false;
}
};
match op {
EqOp::EqAny => regex.iter().any(|r| r.is_match(&item.name)),
EqOp::EqAll => regex.iter().all(|r| r.is_match(&item.name)),
EqOp::NeqAny => !regex.iter().any(|r| r.is_match(&item.name)),
EqOp::NeqAll => !regex.iter().all(|r| r.is_match(&item.name)),
}
}
AlbumRule::Artists { artists, op } => eq_many(item.artists_raw(), artists, *op),
AlbumRule::Discs { count, op } => {
item.disc_total.is_some_and(|v| ord_single(v, *count, *op))
}
AlbumRule::Tracks { count, op } => {
item.track_total.is_some_and(|v| ord_single(v, *count, *op))
}
AlbumRule::Genre { genres, op } => eq_many(&item.genre, genres, *op),
AlbumRule::Date { date, op } => item.date.is_some_and(|v| ord_single(v, *date, *op)),
}
}
}