namespace PLib.Domain.Videos;
/// What a label is for; the relation to videos is identical either way.
public enum LabelKind
{
/// A free-form word used to narrow the grid down.
Tag,
/// A named group the user curates and browses as a whole.
Collection,
}
///
/// A named grouping of videos — a tag or a collection.
///
///
/// Tags and collections are the same relation: a name, many videos, a video in many of them.
/// They differ only in intent, and that intent is . One entity means one
/// join table, one repository and one set of rules about naming; splitting them later is a
/// rename and a migration, whereas keeping two near-identical aggregates in sync from the
/// start is a permanent tax.
///
public sealed class LibraryLabel
{
private readonly List _videos = [];
/// Required by EF Core materialization; do not use from application code.
private LibraryLabel()
{
Name = null!;
NormalizedName = null!;
}
public LibraryLabel(string name, LabelKind kind)
{
ArgumentException.ThrowIfNullOrWhiteSpace(name);
Id = Guid.CreateVersion7();
Kind = kind;
CreatedAt = DateTimeOffset.UtcNow;
Name = name.Trim();
NormalizedName = Normalize(name);
}
public Guid Id { get; private set; }
public string Name { get; private set; }
///
/// Upper-cased, trimmed name. Uniqueness is enforced on this rather than on
/// , so "Комедия" and "комедия" cannot both exist.
///
public string NormalizedName { get; private set; }
public LabelKind Kind { get; private set; }
public DateTimeOffset CreatedAt { get; private set; }
public IReadOnlyCollection Videos => _videos;
public static string Normalize(string name) => name.Trim().ToUpperInvariant();
public void Rename(string name)
{
ArgumentException.ThrowIfNullOrWhiteSpace(name);
Name = name.Trim();
NormalizedName = Normalize(name);
}
}