use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use stateset_primitives::{CustomerId, ProductId, WishlistId};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Wishlist {
pub id: WishlistId,
pub customer_id: CustomerId,
pub name: String,
pub is_public: bool,
pub items: Vec<WishlistItem>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WishlistItem {
pub product_id: ProductId,
pub variant_id: Option<String>,
pub added_at: DateTime<Utc>,
pub note: Option<String>,
pub quantity: u32,
pub priority: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateWishlist {
pub customer_id: CustomerId,
pub name: String,
pub is_public: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddWishlistItem {
pub product_id: ProductId,
pub variant_id: Option<String>,
pub note: Option<String>,
pub quantity: Option<u32>,
pub priority: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct UpdateWishlist {
pub name: Option<String>,
pub is_public: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct WishlistFilter {
pub customer_id: Option<CustomerId>,
pub is_public: Option<bool>,
pub limit: Option<u32>,
pub offset: Option<u32>,
}
impl Wishlist {
#[must_use]
pub fn item_count(&self) -> usize {
self.items.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
#[must_use]
pub fn contains_product(&self, product_id: &ProductId) -> bool {
self.items.iter().any(|item| item.product_id == *product_id)
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::Utc;
use stateset_primitives::{CustomerId, ProductId, WishlistId};
fn make_item(product_id: ProductId) -> WishlistItem {
WishlistItem {
product_id,
variant_id: None,
added_at: Utc::now(),
note: None,
quantity: 1,
priority: None,
}
}
fn make_wishlist(items: Vec<WishlistItem>) -> Wishlist {
Wishlist {
id: WishlistId::new(),
customer_id: CustomerId::new(),
name: "My Wishlist".to_string(),
is_public: false,
items,
created_at: Utc::now(),
updated_at: Utc::now(),
}
}
#[test]
fn item_count_returns_zero_for_empty_wishlist() {
let wl = make_wishlist(vec![]);
assert_eq!(wl.item_count(), 0);
}
#[test]
fn item_count_returns_correct_count() {
let wl = make_wishlist(vec![make_item(ProductId::new()), make_item(ProductId::new())]);
assert_eq!(wl.item_count(), 2);
}
#[test]
fn is_empty_returns_true_for_empty_wishlist() {
let wl = make_wishlist(vec![]);
assert!(wl.is_empty());
}
#[test]
fn is_empty_returns_false_when_items_present() {
let wl = make_wishlist(vec![make_item(ProductId::new())]);
assert!(!wl.is_empty());
}
#[test]
fn contains_product_returns_true_when_present() {
let product_id = ProductId::new();
let wl = make_wishlist(vec![make_item(product_id)]);
assert!(wl.contains_product(&product_id));
}
#[test]
fn contains_product_returns_false_when_absent() {
let wl = make_wishlist(vec![make_item(ProductId::new())]);
let other_id = ProductId::new();
assert!(!wl.contains_product(&other_id));
}
#[test]
fn contains_product_returns_false_for_empty_wishlist() {
let wl = make_wishlist(vec![]);
assert!(!wl.contains_product(&ProductId::new()));
}
}