use std::str::FromStr;
use chrono::{DateTime, Utc};
use lunar_lib::{
database::{Entry, Id},
error,
iterator_ext::IteratorExtensions,
};
use regex::Regex;
use serde::{Deserialize, Serialize};
use crate::library::{
album::Album,
artist::Artist,
collection::rules::{EqOp, OrdOp, Rule, eq_many, eq_single, ord_single},
};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum AlbumRule {
Id { ids: Vec<Id<Album>>, op: EqOp },
Name { regex: Vec<String>, op: EqOp },
Artists { artists: Vec<Id<Artist>>, 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 = Entry<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.title)),
EqOp::EqAll => regex.iter().all(|r| r.is_match(&item.title)),
EqOp::NeqAny => !regex.iter().any(|r| r.is_match(&item.title)),
EqOp::NeqAll => !regex.iter().all(|r| r.is_match(&item.title)),
}
}
AlbumRule::Artists { artists, op } => eq_many(item.artists(), 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)),
}
}
}