using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ExampleFiles.Models;
///
/// Represents an order in an e-commerce system.
/// Demonstrates properties, LINQ, async methods, and C# conventions.
///
public sealed class Order : IEquatable
{
public Guid Id { get; }
public string CustomerEmail { get; init; }
public DateTime CreatedAt { get; }
public OrderStatus Status { get; private set; }
public IReadOnlyList Items => _items.AsReadOnly();
private readonly List _items;
public Order(string customerEmail)
{
Id = Guid.NewGuid();
CustomerEmail = customerEmail ?? throw new ArgumentNullException(nameof(customerEmail));
CreatedAt = DateTime.UtcNow;
Status = OrderStatus.Pending;
_items = new List();
}
// --- Computed properties ---
public decimal Subtotal => _items.Sum(i => i.Total);
public decimal Tax => Math.Round(Subtotal * 0.08m, 2);
public decimal GrandTotal => Subtotal + Tax;
public int TotalQuantity => _items.Sum(i => i.Quantity);
// --- Methods ---
public Order AddItem(string productName, decimal unitPrice, int quantity = 1)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(quantity);
var existing = _items.FirstOrDefault(i =>
i.ProductName.Equals(productName, StringComparison.OrdinalIgnoreCase));
if (existing is not null)
{
existing.Quantity += quantity;
}
else
{
_items.Add(new LineItem(productName, unitPrice, quantity));
}
return this;
}
public bool RemoveItem(string productName)
{
return _items.RemoveAll(i =>
i.ProductName.Equals(productName, StringComparison.OrdinalIgnoreCase)) > 0;
}
public Order Confirm()
{
if (Status != OrderStatus.Pending)
throw new InvalidOperationException($"Cannot confirm an order with status {Status}");
if (!_items.Any())
throw new InvalidOperationException("Cannot confirm an empty order");
Status = OrderStatus.Confirmed;
return this;
}
public Order Cancel(string reason)
{
if (Status == OrderStatus.Shipped || Status == OrderStatus.Delivered)
throw new InvalidOperationException($"Cannot cancel an order that is {Status}");
Status = OrderStatus.Cancelled;
return this;
}
///
/// Simulates sending an order confirmation email asynchronously.
///
public async Task SendConfirmationAsync()
{
await Task.Delay(100); // Simulate network latency
var summary = _items
.Select(i => $" - {i.ProductName} x{i.Quantity}: {i.Total:C}")
.Aggregate((a, b) => $"{a}\n{b}");
return $"Order {Id}\nStatus: {Status}\n\n{summary}\n\nTotal: {GrandTotal:C}";
}
///
/// Returns the top N most expensive line items using LINQ.
///
public IEnumerable TopItemsByValue(int count = 3)
{
return _items
.OrderByDescending(i => i.Total)
.Take(count);
}
// --- Equality ---
public bool Equals(Order? other) => other is not null && Id == other.Id;
public override bool Equals(object? obj) => Equals(obj as Order);
public override int GetHashCode() => Id.GetHashCode();
public override string ToString() =>
$"Order({Id.ToString()[..8]}..., {Status}, {TotalQuantity} items, {GrandTotal:C})";
}
public class LineItem
{
public string ProductName { get; }
public decimal UnitPrice { get; }
public int Quantity { get; set; }
public decimal Total => UnitPrice * Quantity;
public LineItem(string productName, decimal unitPrice, int quantity)
{
ProductName = productName;
UnitPrice = unitPrice;
Quantity = quantity;
}
}
public enum OrderStatus
{
Pending,
Confirmed,
Shipped,
Delivered,
Cancelled
}