using System.Text.Json.Serialization;
using HSchool.Content;
namespace HSchool.People;
/// Stable kind ids written into and listed on .
public static class OffenseKinds
{
public const string Quarrel = "quarrel";
public const string Fight = "fight";
public const string Reprimand = "reprimand";
public static string LocaleKey(string kind) => kind switch
{
Quarrel => "OffenseQuarrel",
Fight => "OffenseFight",
Reprimand => "OffenseReprimand",
_ => "Offense" + char.ToUpperInvariant(kind[0]) + kind[1..],
};
}
/// One remembered misconduct. Sparse list on the person — not a discipline score.
public sealed class OffenseRecord
{
public required string Kind { get; init; }
public required DateTime Time { get; init; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? OtherPersonId { get; init; }
}
/// Appends recent offenses and drops the oldest when over the BehaviorDef ceiling.
public static class OffenseMemory
{
public static bool IsEnabled(string kind, BehaviorDef rules)
{
foreach (var allowed in rules.OffenseMemoryKinds)
{
if (allowed.Equals(kind, StringComparison.Ordinal))
{
return true;
}
}
return false;
}
public static bool Record(Person person, string kind, DateTime time, string? otherPersonId, BehaviorDef rules)
{
ArgumentNullException.ThrowIfNull(person);
ArgumentNullException.ThrowIfNull(rules);
ArgumentException.ThrowIfNullOrWhiteSpace(kind);
if (rules.OffenseMemoryMax <= 0 || !IsEnabled(kind, rules))
{
return false;
}
var list = person.Offenses;
if (list is null)
{
list = [];
person.Offenses = list;
}
list.Add(new OffenseRecord
{
Kind = kind,
Time = DateTime.SpecifyKind(time, DateTimeKind.Utc),
OtherPersonId = string.IsNullOrWhiteSpace(otherPersonId) ? null : otherPersonId,
});
while (list.Count > rules.OffenseMemoryMax)
{
list.RemoveAt(0);
}
return true;
}
public static string? OtherParticipant(string personId, string? victimId, IReadOnlyList members)
{
if (victimId is not null
&& !victimId.Equals(personId, StringComparison.Ordinal)
&& members.Contains(victimId, StringComparer.Ordinal))
{
return victimId;
}
foreach (var member in members)
{
if (!member.Equals(personId, StringComparison.Ordinal))
{
return member;
}
}
return null;
}
}