using System.Text.Json.Serialization; namespace RpgRoller.Contracts; public sealed record HealthResponse(string Status); public sealed record ApiError(string Error, string? Code = null); public sealed record RegisterRequest(string Username, string Password, string DisplayName); public sealed record LoginRequest(string Username, string Password); public sealed record UserSummary(Guid Id, string Username, string DisplayName, IReadOnlyList Roles); public sealed record MeResponse(UserSummary User, Guid? ActiveCharacterId, Guid? CurrentCampaignId); public sealed record AdminUserSummary(Guid Id, string Username, string DisplayName, IReadOnlyList Roles); public sealed record UpdateUserRolesRequest(IReadOnlyList Roles); public sealed record RulesetDefinition(string Id, string Name, string DiceSyntax); public sealed record CreateCampaignRequest(string Name, string RulesetId); public sealed record CampaignGmSummary(Guid Id, string DisplayName); public sealed record CampaignSummary(Guid Id, string Name, string RulesetId, CampaignGmSummary Gm, int CharacterCount); public sealed record CampaignRoster(Guid Id, string Name, string RulesetId, CampaignGmSummary Gm, CharacterSummary[] Characters); public sealed record CampaignOption(Guid Id, string Name); public sealed record CreateCharacterRequest(string Name, Guid CampaignId); public sealed record UpdateCharacterRequest(string Name, Guid? CampaignId, string? OwnerUsername = null); public sealed record CharacterSummary(Guid Id, string Name, Guid OwnerUserId, Guid? CampaignId, string OwnerDisplayName); public sealed record CreateSkillRequest(string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, Guid? SkillGroupId = null, int? FumbleRange = null, bool RolemasterAutoRetry = false); public sealed record UpdateSkillRequest(string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, Guid? SkillGroupId = null, int? FumbleRange = null, bool RolemasterAutoRetry = false); public sealed record SkillGroupSummary(Guid Id, Guid CharacterId, string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, int? FumbleRange); public sealed record CreateSkillGroupRequest(string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, int? FumbleRange = null); public sealed record UpdateSkillGroupRequest(string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, int? FumbleRange = null); public sealed record SkillSummary(Guid Id, Guid CharacterId, Guid? SkillGroupId, string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry); public sealed record RollSkillRequest(string Visibility, int SituationalModifier = 0); public sealed record CustomRollRequest(string Expression, string Visibility); public static class RollDieKinds { public const string RolemasterStandard = "rolemaster-standard"; public const string RolemasterOpenEndedInitial = "rolemaster-open-ended-initial"; public const string RolemasterOpenEndedHigh = "rolemaster-open-ended-high"; public const string RolemasterOpenEndedLowSubtract = "rolemaster-open-ended-low-subtract"; } public sealed record RollDieResult { public RollDieResult() { } public RollDieResult(int roll, bool crit, bool fumble, bool wild, bool removed, bool added, int? sequence = null, string? kind = null, int? signedContribution = null, int? attempt = null) { Roll = roll; Crit = crit; Fumble = fumble; Wild = wild; Removed = removed; Added = added; Sequence = sequence; Kind = kind; SignedContribution = signedContribution; Attempt = attempt; } public int Roll { get; init; } public bool Crit { get; init; } public bool Fumble { get; init; } public bool Wild { get; init; } public bool Removed { get; init; } public bool Added { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? Sequence { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? Kind { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? SignedContribution { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? Attempt { get; init; } } public sealed record RollResult(Guid RollId, Guid CampaignId, Guid CharacterId, Guid SkillId, Guid RollerUserId, string Visibility, int Result, string Breakdown, IReadOnlyList Dice, DateTimeOffset TimestampUtc); public sealed record CharacterSheetSkillGroup(Guid Id, string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, int? FumbleRange); public sealed record CharacterSheetSkill(Guid Id, Guid? SkillGroupId, string Name, string DiceRollDefinition, int WildDice, bool AllowFumble, int? FumbleRange, bool RolemasterAutoRetry); public sealed record CharacterSheet(Guid CharacterId, CharacterSheetSkillGroup[] SkillGroups, CharacterSheetSkill[] Skills); public sealed record CampaignLogEntry(Guid RollId, Guid CampaignId, Guid CharacterId, string CharacterName, Guid SkillId, string SkillName, Guid RollerUserId, string RollerDisplayName, string Visibility, int Result, string Breakdown, IReadOnlyList Dice, DateTimeOffset TimestampUtc); public sealed record CampaignLogListEntry( Guid RollId, string CharacterName, string SkillName, string RollerLabel, string VisibilityLabel, string VisibilityStyle, int Result, string SummaryText, [property: JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] string[]? EventBadges, DateTimeOffset TimestampUtc); public sealed record CampaignRollDetail(Guid RollId, string Breakdown, RollDieResult[] Dice); public sealed record CharacterStateVersion(Guid CharacterId, long Version); public sealed record CampaignStateSnapshot(Guid CampaignId, long TotalVersion, long RosterVersion, long LogVersion, IReadOnlyList CharacterVersions); public sealed record CampaignLogPage(CampaignLogListEntry[] Entries, Guid? Cursor, bool HasMore, bool ResetRequired);