namespace PlotLine.Models; public static class BookTitleFormatter { public static string DisplayTitle(string? title, string? subtitle) { if (string.IsNullOrWhiteSpace(title)) { return string.Empty; } return string.IsNullOrWhiteSpace(subtitle) ? title : $"{title}: {subtitle}"; } } public sealed class Project { public int ProjectID { get; set; } public string ProjectName { get; set; } = string.Empty; public string? Description { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } public string AccessRole { get; set; } = "Owner"; public bool IsOwner => string.Equals(AccessRole, "Owner", StringComparison.OrdinalIgnoreCase); } public sealed class ProjectCollaborator { public int ProjectUserAccessID { get; set; } public int ProjectID { get; set; } public int UserID { get; set; } public string Email { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public string AccessRole { get; set; } = "Collaborator"; public int? InvitedByUserID { get; set; } public string? InvitedByDisplayName { get; set; } public DateTime? InvitedDateUTC { get; set; } public DateTime? AcceptedDateUTC { get; set; } public bool IsActive { get; set; } } public sealed class ProjectInvitation { public int ProjectInvitationID { get; set; } public int ProjectID { get; set; } public string EmailAddress { get; set; } = string.Empty; public string AccessRole { get; set; } = "Collaborator"; public Guid InvitationToken { get; set; } public int InvitedByUserID { get; set; } public string? InvitedByDisplayName { get; set; } public DateTime InvitedDateUTC { get; set; } public DateTime? AcceptedDateUTC { get; set; } public int? AcceptedByUserID { get; set; } public bool IsAccepted { get; set; } public bool IsCancelled { get; set; } public DateTime? CancelledDateUTC { get; set; } } public sealed class ProjectActivity { public long ProjectActivityID { get; set; } public int ProjectID { get; set; } public int? UserID { get; set; } public string? DisplayName { get; set; } public string? Email { get; set; } public string ActivityType { get; set; } = string.Empty; public string EntityType { get; set; } = string.Empty; public int? EntityID { get; set; } public string? EntityName { get; set; } public string? Description { get; set; } public DateTime CreatedDateUTC { get; set; } public string UserLabel => !string.IsNullOrWhiteSpace(DisplayName) ? DisplayName : !string.IsNullOrWhiteSpace(Email) ? Email : "System"; } public sealed class ProjectDashboardMetrics { public int CharacterCount { get; set; } public int LocationCount { get; set; } public int ActivePlotThreadCount { get; set; } public int ContinuityWarningCount { get; set; } } public sealed class ProjectDashboardAttentionThread { public int PlotThreadID { get; set; } public string ThreadTitle { get; set; } = string.Empty; public int PlotLineID { get; set; } public string PlotLineName { get; set; } = string.Empty; public int Importance { get; set; } public string ThreadStatusName { get; set; } = string.Empty; public bool IsOpenStatus { get; set; } public bool IsResolvedStatus { get; set; } } public sealed class ProjectHardDeleteResult { public bool Succeeded { get; init; } public bool NotFound { get; init; } public bool NotArchived { get; init; } public bool FileCleanupHadFailures { get; init; } public int DeletedFileCount { get; init; } public int MissingFileCount { get; init; } public int FailedFileCount { get; init; } public string Message { get; init; } = string.Empty; public static ProjectHardDeleteResult Success(int deletedFileCount, int missingFileCount, int failedFileCount) => new() { Succeeded = true, FileCleanupHadFailures = failedFileCount > 0, DeletedFileCount = deletedFileCount, MissingFileCount = missingFileCount, FailedFileCount = failedFileCount, Message = failedFileCount > 0 ? "Project permanently deleted, but some files could not be removed. Check the application logs." : "Project permanently deleted." }; public static ProjectHardDeleteResult Inaccessible() => new() { NotFound = true, Message = "Project not found." }; public static ProjectHardDeleteResult ActiveProject() => new() { NotArchived = true, Message = "Only archived projects can be permanently deleted." }; public static ProjectHardDeleteResult Failure(string message) => new() { Message = message }; } public sealed class UserFile { public long UserFileID { get; set; } public int UserID { get; set; } public int? ProjectID { get; set; } public string EntityType { get; set; } = string.Empty; public int EntityID { get; set; } public string FileName { get; set; } = string.Empty; public string? OriginalFileName { get; set; } public string? ContentType { get; set; } public long FileSizeBytes { get; set; } public string StoragePath { get; set; } = string.Empty; public DateTime UploadedDateUTC { get; set; } public DateTime? DeletedDateUTC { get; set; } public bool IsDeleted { get; set; } } public sealed class StorageUsage { public long UsedBytes { get; init; } public long MaximumBytes { get; init; } public string UsedLabel => FormatBytes(UsedBytes); public string MaximumLabel => MaximumBytes >= 999999L * 1024L * 1024L ? "Unrestricted" : FormatBytes(MaximumBytes); public string DisplayLabel => $"{UsedLabel} / {MaximumLabel}"; public static string FormatBytes(long bytes) { if (bytes >= 1024L * 1024L * 1024L) { return $"{bytes / (1024d * 1024d * 1024d):0.##} GB"; } if (bytes >= 1024L * 1024L) { return $"{bytes / (1024d * 1024d):0.##} MB"; } if (bytes >= 1024L) { return $"{bytes / 1024d:0.##} KB"; } return $"{bytes:N0} bytes"; } } public sealed class StorageLimitResult { public bool Allowed { get; init; } public long CurrentUsageBytes { get; init; } public long MaximumAllowedBytes { get; init; } public string Message { get; init; } = string.Empty; public static StorageLimitResult AllowedResult(long currentUsageBytes, long maximumAllowedBytes) => new() { Allowed = true, CurrentUsageBytes = currentUsageBytes, MaximumAllowedBytes = maximumAllowedBytes }; public static StorageLimitResult Blocked(long currentUsageBytes, long maximumAllowedBytes, long uploadBytes) => new() { Allowed = false, CurrentUsageBytes = currentUsageBytes, MaximumAllowedBytes = maximumAllowedBytes, Message = $"You have used {StorageUsage.FormatBytes(currentUsageBytes)} of your {StorageUsage.FormatBytes(maximumAllowedBytes)} storage allowance. Uploading this {StorageUsage.FormatBytes(uploadBytes)} file would exceed your subscription limit." }; } public sealed class GenreMetricPreset { public int GenreMetricPresetID { get; set; } public string PresetKey { get; set; } = string.Empty; public string PresetName { get; set; } = string.Empty; public string? Description { get; set; } public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class Book { public int BookID { get; set; } public int ProjectID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? Subtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, Subtitle); public string? Tagline { get; set; } public string? ShortDescription { get; set; } public string Status { get; set; } = BookStatuses.Planning; public int BookNumber { get; set; } public string? Description { get; set; } public int? TargetWordCount { get; set; } public DateTime? WritingStartDate { get; set; } public DateTime? TargetCompletionDate { get; set; } public DateTime? PublicationDate { get; set; } public bool UsesExplicitScenes { get; set; } public string? CoverThumbnailPath { get; set; } public string? CoverStandardPath { get; set; } public int CurrentWordCount { get; set; } public int ChapterCount { get; set; } public int SceneCount { get; set; } public int SortOrder { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } public decimal? ProgressPercentage => TargetWordCount is > 0 ? Math.Min(100m, Math.Round(CurrentWordCount * 100m / TargetWordCount.Value, 1)) : null; } public sealed class ManuscriptDocumentModel { public int ManuscriptDocumentID { get; set; } public int BookID { get; set; } public int ProjectID { get; set; } public Guid DocumentGuid { get; set; } public int BindingVersion { get; set; } = 1; public DateTime CreatedUtc { get; set; } public DateTime? LastSyncUtc { get; set; } public DateTime? LastOpenedUtc { get; set; } public bool IsActive { get; set; } = true; public int? CreatedByUserID { get; set; } } public sealed class ManuscriptDocumentUnlinkResult { public int BookID { get; set; } public int ManuscriptDocumentID { get; set; } public int ChaptersUnlinked { get; set; } public int ScenesUnlinked { get; set; } public string Message { get; set; } = string.Empty; } public sealed class CharacterAlias { public int CharacterAliasID { get; set; } public int CharacterID { get; set; } public string Alias { get; set; } = string.Empty; public int SortOrder { get; set; } public DateTime CreatedUtc { get; set; } } public sealed class AssetAlias { public int AssetAliasID { get; set; } public int StoryAssetID { get; set; } public string Alias { get; set; } = string.Empty; public int SortOrder { get; set; } public DateTime CreatedUtc { get; set; } } public sealed class LocationAlias { public int LocationAliasID { get; set; } public int LocationID { get; set; } public string Alias { get; set; } = string.Empty; public int SortOrder { get; set; } public DateTime CreatedUtc { get; set; } } public static class BookStatuses { public const string Planning = "Planning"; public const string Research = "Research"; public const string Outlining = "Outlining"; public const string Drafting = "Drafting"; public const string Revising = "Revising"; public const string Editing = "Editing"; public const string Proofreading = "Proofreading"; public const string ReadyForPublication = "Ready for Publication"; public const string Published = "Published"; public const string Paused = "Paused"; public const string Archived = "Archived"; public static readonly IReadOnlyList All = [ Planning, Research, Outlining, Drafting, Revising, Editing, Proofreading, ReadyForPublication, Published, Paused, Archived ]; public static bool IsValid(string? status) => All.Contains(status ?? string.Empty, StringComparer.OrdinalIgnoreCase); } public sealed class Chapter { public int ChapterID { get; set; } public int BookID { get; set; } public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public int? POVCharacterID { get; set; } public string? Summary { get; set; } public int? ChapterPurposeID { get; set; } public string? ChapterPurposeName { get; set; } public int SortOrder { get; set; } public int RevisionStatusID { get; set; } public string RevisionStatusName { get; set; } = string.Empty; public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } public bool IsLinkedToManuscript { get; set; } public int? ManuscriptDocumentID { get; set; } public string? ExternalReference { get; set; } public DateTime? LinkedUtc { get; set; } } public sealed class Scene { public int SceneID { get; set; } public int ChapterID { get; set; } public int BookID { get; set; } public int BookNumber { get; set; } public int BookSortOrder { get; set; } public string? BookTitle { get; set; } public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public decimal ChapterNumber { get; set; } public int ChapterSortOrder { get; set; } public string? ChapterTitle { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public string? Summary { get; set; } public int? POVCharacterID { get; set; } public int? PrimaryLocationID { get; set; } public int? FloorPlanID { get; set; } public int? InitialFloorPlanFloorID { get; set; } public string? PrimaryLocationName { get; set; } public string? PrimaryLocationPath { get; set; } public int SortOrder { get; set; } public int TimeModeID { get; set; } public string TimeModeName { get; set; } = string.Empty; public DateTime? StartDateTime { get; set; } public DateTime? EndDateTime { get; set; } public decimal? DurationAmount { get; set; } public int? DurationUnitID { get; set; } public string? DurationUnitName { get; set; } public string? RelativeTimeText { get; set; } public int TimeConfidenceID { get; set; } public string TimeConfidenceName { get; set; } = string.Empty; public string? ScenePurposeNotes { get; set; } public string? SceneOutcomeNotes { get; set; } public int RevisionStatusID { get; set; } public string RevisionStatusName { get; set; } = string.Empty; public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } public bool IsLinkedToManuscript { get; set; } public int? ManuscriptDocumentID { get; set; } public string? ExternalReference { get; set; } public DateTime? LinkedUtc { get; set; } public string? ImportSource { get; set; } public int? ImportRunID { get; set; } public int? SourceStartParagraph { get; set; } public int? SourceEndParagraph { get; set; } public List SelectedPurposeTypeIds { get; set; } = []; public List PurposeLabels { get; set; } = []; public List Metrics { get; set; } = []; public int WarningCount { get; set; } public int DependencyCount { get; set; } public int PendingCharacterSuggestionCount { get; set; } public int PendingAssetSuggestionCount { get; set; } public int PendingLocationSuggestionCount { get; set; } public string TimeLabel { get { if (!string.IsNullOrWhiteSpace(RelativeTimeText)) { return RelativeTimeText; } return StartDateTime?.ToString(TimeModeName == "Exact Date" ? "dd MMM yyyy" : "dd MMM yyyy HH:mm") ?? TimeModeName; } } } public sealed class RevisionStatus { public int RevisionStatusID { get; set; } public string StatusName { get; set; } = string.Empty; public int SortOrder { get; set; } } public sealed class ChapterPurposeType { public int ChapterPurposeID { get; set; } public string PurposeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsArchived { get; set; } } public sealed class TimeMode { public int TimeModeID { get; set; } public string TimeModeName { get; set; } = string.Empty; public int SortOrder { get; set; } } public sealed class DurationUnit { public int DurationUnitID { get; set; } public string DurationUnitName { get; set; } = string.Empty; public int SortOrder { get; set; } } public sealed class TimeConfidence { public int TimeConfidenceID { get; set; } public string TimeConfidenceName { get; set; } = string.Empty; public int SortOrder { get; set; } } public sealed class ScenePurposeType { public int ScenePurposeTypeID { get; set; } public string PurposeName { get; set; } = string.Empty; public int SortOrder { get; set; } } public sealed class ScenePurposeLabel { public int SceneID { get; set; } public int ScenePurposeTypeID { get; set; } public string PurposeName { get; set; } = string.Empty; public int SortOrder { get; set; } } public sealed class SceneMetricType { public int MetricTypeID { get; set; } public int? ProjectID { get; set; } public string MetricName { get; set; } = string.Empty; public string? Description { get; set; } public int MinValue { get; set; } public int MaxValue { get; set; } public int DefaultValue { get; set; } public int SortOrder { get; set; } public bool IsActive { get; set; } public bool IsEnabledForProject { get; set; } public bool IsCustom { get; set; } public string? GenrePresetKeys { get; set; } public string? GenrePresetNames { get; set; } public int ValueCount { get; set; } } public sealed class SceneMetricValue { public int SceneID { get; set; } public int MetricTypeID { get; set; } public string MetricName { get; set; } = string.Empty; public string? Description { get; set; } public int MinValue { get; set; } public int MaxValue { get; set; } public int DefaultValue { get; set; } public int SortOrder { get; set; } public bool IsActive { get; set; } public int Value { get; set; } public string? Notes { get; set; } } public sealed class TimelineMetricPoint { public int SceneID { get; set; } public int MetricTypeID { get; set; } public string MetricName { get; set; } = string.Empty; public int Value { get; set; } public string? Notes { get; set; } } public sealed class TimelineViewPreset { public int TimelineViewPresetID { get; set; } public int ProjectID { get; set; } public int? BookID { get; set; } public string PresetName { get; set; } = string.Empty; public string FilterJson { get; set; } = "{}"; public string VisibilityJson { get; set; } = "{}"; public string? FocusType { get; set; } public int? FocusID { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } } public sealed class ProjectTimelineSettings { public int ProjectTimelineSettingsID { get; set; } public int ProjectID { get; set; } public bool ShowSceneCards { get; set; } = true; public bool ShowMetricShape { get; set; } = true; public bool ShowPlotLines { get; set; } = true; public bool ShowStoryAssets { get; set; } public bool ShowCharacterAppearances { get; set; } public bool ShowWarnings { get; set; } = true; public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class ProjectTimelineMetricSetting { public int ProjectID { get; set; } public int MetricTypeID { get; set; } public string MetricName { get; set; } = string.Empty; public int SortOrder { get; set; } public DateTime CreatedDate { get; set; } } public sealed class PlotLineType { public int PlotLineTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class PlotImportance { public int PlotImportanceID { get; set; } public string ImportanceName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class PlotLineItem { public int PlotLineID { get; set; } public int ProjectID { get; set; } public int? BookID { get; set; } public string? BookTitle { get; set; } public string PlotLineName { get; set; } = string.Empty; public int PlotLineTypeID { get; set; } public string PlotLineTypeName { get; set; } = string.Empty; public int PlotImportanceID { get; set; } = 2; public string PlotImportanceName { get; set; } = "Secondary"; public string? Description { get; set; } public int? ParentPlotLineID { get; set; } public string? ParentPlotLineName { get; set; } public int? EmergesFromPlotLineID { get; set; } public string? EmergesFromPlotLineName { get; set; } public int SortOrder { get; set; } public string Colour { get; set; } = "#2f6f63"; public bool IsVisibleOnTimeline { get; set; } = true; public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } } public sealed class ThreadType { public int ThreadTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class ThreadStatus { public int ThreadStatusID { get; set; } public string StatusName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsOpenStatus { get; set; } public bool IsResolvedStatus { get; set; } public bool IsActive { get; set; } } public sealed class PlotThread { public int PlotThreadID { get; set; } public int PlotLineID { get; set; } public int ProjectID { get; set; } public string PlotLineName { get; set; } = string.Empty; public string ThreadTitle { get; set; } = string.Empty; public int ThreadTypeID { get; set; } public string ThreadTypeName { get; set; } = string.Empty; public int ThreadStatusID { get; set; } public string ThreadStatusName { get; set; } = string.Empty; public int Importance { get; set; } = 5; public string? Summary { get; set; } public int? IntroducedSceneID { get; set; } public int? PlannedResolutionSceneID { get; set; } public int? ActualResolutionSceneID { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } } public sealed class ThreadEventType { public int ThreadEventTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public string MarkerText { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class PlotEventType { public int PlotEventTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class ThreadEvent { public int ThreadEventID { get; set; } public int PlotThreadID { get; set; } public string ThreadTitle { get; set; } = string.Empty; public int PlotLineID { get; set; } public string PlotLineName { get; set; } = string.Empty; public string Colour { get; set; } = "#2f6f63"; public int SceneID { get; set; } public int EventTypeID { get; set; } public string EventTypeName { get; set; } = string.Empty; public string MarkerText { get; set; } = string.Empty; public string ThreadStatusName { get; set; } = string.Empty; public int Importance { get; set; } public int PlotEventTypeID { get; set; } = 2; public string PlotEventTypeName { get; set; } = "Progress"; public int? TargetPlotLineID { get; set; } public string? TargetPlotLineName { get; set; } public IReadOnlyList TargetPlotLineIDs { get; set; } = []; public string EventTitle { get; set; } = string.Empty; public string? EventDescription { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class PlotEventTargetPlotLine { public int PlotEventID { get; set; } public int PlotLineID { get; set; } public DateTime CreatedDate { get; set; } } public sealed class SceneOption { public int SceneID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; } public sealed class PlotLookupData { public IReadOnlyList PlotLineTypes { get; init; } = []; public IReadOnlyList PlotImportance { get; init; } = []; public IReadOnlyList ThreadTypes { get; init; } = []; public IReadOnlyList ThreadStatuses { get; init; } = []; public IReadOnlyList ThreadEventTypes { get; init; } = []; public IReadOnlyList PlotEventTypes { get; init; } = []; } public sealed class AssetKind { public int AssetKindID { get; set; } public string KindName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class AssetState { public int AssetStateID { get; set; } public int? ProjectID { get; set; } public int? AssetKindID { get; set; } public string? KindName { get; set; } public string StateName { get; set; } = string.Empty; public int SortOrder { get; set; } public string? Description { get; set; } public bool IsResolvedState { get; set; } public bool IsActive { get; set; } } public sealed class StoryAsset { public int StoryAssetID { get; set; } public int ProjectID { get; set; } public string AssetName { get; set; } = string.Empty; public int AssetKindID { get; set; } public string KindName { get; set; } = string.Empty; public string? Description { get; set; } public int Importance { get; set; } = 5; public int? CurrentStateID { get; set; } public string? CurrentStateName { get; set; } public int? CurrentLocationID { get; set; } public string? CurrentLocationName { get; set; } public string? CurrentLocationPath { get; set; } public bool IsResolved { get; set; } public bool ShowInQuickAddBar { get; set; } public string? ImagePath { get; set; } public string? ThumbnailPath { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } } public sealed class AssetEventType { public int AssetEventTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public string MarkerText { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class AssetEvent { public int AssetEventID { get; set; } public int StoryAssetID { get; set; } public int ProjectID { get; set; } public string AssetName { get; set; } = string.Empty; public int AssetKindID { get; set; } public string KindName { get; set; } = string.Empty; public int SceneID { get; set; } public int AssetEventTypeID { get; set; } public string AssetEventTypeName { get; set; } = string.Empty; public string MarkerText { get; set; } = string.Empty; public int? FromStateID { get; set; } public string? FromStateName { get; set; } public int? ToStateID { get; set; } public string? ToStateName { get; set; } public string EventTitle { get; set; } = string.Empty; public string? EventDescription { get; set; } public string? BookTitle { get; set; } public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public decimal ChapterNumber { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class AssetDependencyType { public int AssetDependencyTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsValidatingDependency { get; set; } public bool IsActive { get; set; } } public sealed class AssetDependency { public int AssetDependencyID { get; set; } public int SourceAssetID { get; set; } public string SourceAssetName { get; set; } = string.Empty; public int TargetAssetID { get; set; } public string TargetAssetName { get; set; } = string.Empty; public int AssetDependencyTypeID { get; set; } public string DependencyTypeName { get; set; } = string.Empty; public bool IsValidatingDependency { get; set; } public int? SourceRequiredStateID { get; set; } public string? SourceRequiredStateName { get; set; } public int? TargetBlockedStateID { get; set; } public string? TargetBlockedStateName { get; set; } public string? Description { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } } public sealed class AssetCustodyEventType { public int AssetCustodyEventTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class CustodyRole { public int CustodyRoleID { get; set; } public string RoleName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class AssetCustodyEvent { public int AssetCustodyEventID { get; set; } public int StoryAssetID { get; set; } public string AssetName { get; set; } = string.Empty; public int SceneID { get; set; } public int AssetCustodyEventTypeID { get; set; } public string CustodyEventTypeName { get; set; } = string.Empty; public string? Description { get; set; } public string? CustodianSummary { get; set; } public string? BookTitle { get; set; } public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public decimal ChapterNumber { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class AssetCustodyCharacter { public int AssetCustodyEventID { get; set; } public int StoryAssetID { get; set; } public int SceneID { get; set; } public int? CharacterID { get; set; } public string? CharacterName { get; set; } public string? CharacterNameText { get; set; } public string RoleName { get; set; } = string.Empty; public DateTime UpdatedDate { get; set; } } public sealed class AssetDependencyIssue { public int AssetDependencyID { get; set; } public string SourceAssetName { get; set; } = string.Empty; public string TargetAssetName { get; set; } = string.Empty; public string DependencyTypeName { get; set; } = string.Empty; public string? SourceRequiredStateName { get; set; } public string? TargetBlockedStateName { get; set; } public string? Description { get; set; } } public sealed class AssetLookupData { public IReadOnlyList AssetKinds { get; init; } = []; public IReadOnlyList AssetStates { get; init; } = []; public IReadOnlyList AssetEventTypes { get; init; } = []; public IReadOnlyList AssetDependencyTypes { get; init; } = []; public IReadOnlyList AssetCustodyEventTypes { get; init; } = []; public IReadOnlyList CustodyRoles { get; init; } = []; } public sealed class Character { public int CharacterID { get; set; } public int ProjectID { get; set; } public string CharacterName { get; set; } = string.Empty; public string? ShortName { get; set; } public int? SexValueID { get; set; } public string? Sex { get; set; } public DateTime? BirthDate { get; set; } public int? AgeAtSeriesStart { get; set; } public int? AgeReferenceSceneID { get; set; } public string? Height { get; set; } public string? EyeColour { get; set; } public int? CharacterImportance { get; set; } public bool ShowInQuickAddBar { get; set; } public string? DefaultDescription { get; set; } public string? ImagePath { get; set; } public string? ThumbnailPath { get; set; } public int? AvatarSourceCharacterImageID { get; set; } public string? AvatarImagePath { get; set; } public string? AvatarThumbnailPath { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } } public sealed class CharacterSexValue { public int CharacterSexValueID { get; set; } public int? OwnerUserID { get; set; } public string SexName { get; set; } = string.Empty; public bool IsSystem { get; set; } public int SortOrder { get; set; } public bool IsActive { get; set; } = true; } public sealed class CharacterImage { public int CharacterImageID { get; set; } public int CharacterID { get; set; } public int ProjectID { get; set; } public string ImagePath { get; set; } = string.Empty; public string ThumbnailPath { get; set; } = string.Empty; public string? Caption { get; set; } public int SortOrder { get; set; } public DateTime UploadedDateUTC { get; set; } public bool IsDeleted { get; set; } } public sealed class CharacterRoleInSceneType { public int CharacterRoleInSceneTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class PresenceType { public int PresenceTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class SceneCharacter { public int SceneCharacterID { get; set; } public int SceneID { get; set; } public int CharacterID { get; set; } public int ProjectID { get; set; } public string CharacterName { get; set; } = string.Empty; public string? ShortName { get; set; } public string? CharacterImagePath { get; set; } public string? CharacterThumbnailPath { get; set; } public DateTime? BirthDate { get; set; } public int? AgeAtSeriesStart { get; set; } public int? RoleInSceneTypeID { get; set; } public string? RoleInSceneTypeName { get; set; } public int? PresenceTypeID { get; set; } public string? PresenceTypeName { get; set; } public int? LocationID { get; set; } public string? LocationName { get; set; } public string? LocationPath { get; set; } public int? EntryLocationID { get; set; } public string? EntryLocationName { get; set; } public int? ExitLocationID { get; set; } public string? ExitLocationName { get; set; } public string? AppearanceNotes { get; set; } public string? OutfitDescription { get; set; } public string? PhysicalCondition { get; set; } public string? EmotionalState { get; set; } public string? KnowledgeNotes { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public decimal ChapterNumber { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class SceneCharacterSuggestion { public int SceneCharacterSuggestionID { get; set; } public int SceneID { get; set; } public int CharacterID { get; set; } public string CharacterName { get; set; } = string.Empty; public string Status { get; set; } = string.Empty; public string Confidence { get; set; } = string.Empty; public string? Reason { get; set; } public DateTime DetectedUtc { get; set; } } public sealed class SceneCharacterSuggestionCount { public int SceneID { get; set; } public int PendingSuggestionCount { get; set; } } public sealed class SceneCharacterSuggestionReviewResult { public int SceneCharacterSuggestionID { get; set; } public int SceneID { get; set; } public int CharacterID { get; set; } public string Status { get; set; } = string.Empty; public bool SceneCharacterCreated { get; set; } } public sealed class SceneAssetSuggestion { public int SceneAssetSuggestionID { get; set; } public int SceneID { get; set; } public int AssetID { get; set; } public string AssetName { get; set; } = string.Empty; public string Status { get; set; } = string.Empty; public string Confidence { get; set; } = string.Empty; public string? Reason { get; set; } public DateTime DetectedUtc { get; set; } } public sealed class SceneAssetSuggestionCount { public int SceneID { get; set; } public int PendingSuggestionCount { get; set; } } public sealed class SceneAssetSuggestionReviewResult { public int SceneAssetSuggestionID { get; set; } public int SceneID { get; set; } public int AssetID { get; set; } public string Status { get; set; } = string.Empty; public bool SceneAssetCreated { get; set; } } public sealed class SceneLocationSuggestion { public int SceneLocationSuggestionID { get; set; } public int SceneID { get; set; } public int LocationID { get; set; } public string LocationName { get; set; } = string.Empty; public string LocationPath { get; set; } = string.Empty; public string Status { get; set; } = string.Empty; public string Confidence { get; set; } = string.Empty; public string? Reason { get; set; } public DateTime DetectedUtc { get; set; } } public sealed class SceneLocationSuggestionCount { public int SceneID { get; set; } public int PendingSuggestionCount { get; set; } } public sealed class SceneLocationSuggestionReviewResult { public int SceneLocationSuggestionID { get; set; } public int SceneID { get; set; } public int LocationID { get; set; } public string Status { get; set; } = string.Empty; public bool SceneLocationCreated { get; set; } public bool PrimaryLocationUpdated { get; set; } } public sealed class CharacterAttributeType { public int CharacterAttributeTypeID { get; set; } public int? ProjectID { get; set; } public string AttributeName { get; set; } = string.Empty; public string DataType { get; set; } = "Text"; public bool IsNormallyStable { get; set; } public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class CharacterAttributeEvent { public int CharacterAttributeEventID { get; set; } public int CharacterID { get; set; } public string CharacterName { get; set; } = string.Empty; public int CharacterAttributeTypeID { get; set; } public string AttributeName { get; set; } = string.Empty; public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public decimal ChapterNumber { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public string AttributeValue { get; set; } = string.Empty; public string? Description { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class KnowledgeState { public int KnowledgeStateID { get; set; } public string StateName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class CharacterKnowledgeItem { public int CharacterKnowledgeID { get; set; } public int CharacterID { get; set; } public string CharacterName { get; set; } = string.Empty; public int? StoryAssetID { get; set; } public string? AssetName { get; set; } public int? PlotThreadID { get; set; } public string? ThreadTitle { get; set; } public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public decimal ChapterNumber { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int KnowledgeStateID { get; set; } public string KnowledgeStateName { get; set; } = string.Empty; public int? SourceEventID { get; set; } public string? Description { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class RelationshipType { public int RelationshipTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public bool IsPermanentDefault { get; set; } public int SortOrder { get; set; } public bool IsActive { get; set; } public int RelationshipCategoryID { get; set; } public string RelationshipCategoryName { get; set; } = "Other"; public int CategorySortOrder { get; set; } } public sealed class RelationshipCategory { public int RelationshipCategoryID { get; set; } public string CategoryName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class RelationshipState { public int RelationshipStateID { get; set; } public string StateName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class CharacterRelationship { public int CharacterRelationshipID { get; set; } public int ProjectID { get; set; } public int CharacterAID { get; set; } public string CharacterAName { get; set; } = string.Empty; public int CharacterBID { get; set; } public string CharacterBName { get; set; } = string.Empty; public int RelationshipTypeID { get; set; } public string RelationshipTypeName { get; set; } = string.Empty; public int RelationshipCategoryID { get; set; } public string RelationshipCategoryName { get; set; } = "Other"; public int CategorySortOrder { get; set; } public int RelationshipTypeSortOrder { get; set; } public bool IsPermanent { get; set; } public int? StartSceneID { get; set; } public int? EndSceneID { get; set; } public bool IsKnownToReader { get; set; } public string? Notes { get; set; } public bool IsInitialRelationship { get; set; } public int? InitialBookID { get; set; } public string? InitialBookTitle { get; set; } public string? InitialBookSubtitle { get; set; } public string InitialBookDisplayTitle => BookTitleFormatter.DisplayTitle(InitialBookTitle, InitialBookSubtitle); public bool ReaderInitiallyKnows { get; set; } public int? InitialRelationshipStateID { get; set; } public string? InitialRelationshipStateName { get; set; } public int? InitialIntensity { get; set; } public bool IsReciprocal { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } } public sealed class RelationshipEvent { public int RelationshipEventID { get; set; } public int CharacterRelationshipID { get; set; } public int ProjectID { get; set; } public int CharacterAID { get; set; } public string CharacterAName { get; set; } = string.Empty; public int CharacterBID { get; set; } public string CharacterBName { get; set; } = string.Empty; public string RelationshipTypeName { get; set; } = string.Empty; public int RelationshipCategoryID { get; set; } public string RelationshipCategoryName { get; set; } = "Other"; public int CategorySortOrder { get; set; } public int RelationshipTypeSortOrder { get; set; } public bool IsReciprocal { get; set; } public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public decimal ChapterNumber { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int RelationshipStateID { get; set; } public string RelationshipStateName { get; set; } = string.Empty; public int? Intensity { get; set; } public bool IsKnownToOtherCharacter { get; set; } public string? Description { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class CharacterLookupData { public IReadOnlyList RoleTypes { get; init; } = []; public IReadOnlyList PresenceTypes { get; init; } = []; public IReadOnlyList AttributeTypes { get; init; } = []; public IReadOnlyList KnowledgeStates { get; init; } = []; public IReadOnlyList RelationshipTypes { get; init; } = []; public IReadOnlyList RelationshipStates { get; init; } = []; public IReadOnlyList RelationshipCategories { get; init; } = []; } public sealed class RelationshipMapData { public IReadOnlyList Characters { get; init; } = []; public IReadOnlyList Books { get; init; } = []; public IReadOnlyList Chapters { get; init; } = []; public IReadOnlyList Scenes { get; init; } = []; public IReadOnlyList Relationships { get; init; } = []; public IReadOnlyList RelationshipEvents { get; init; } = []; public IReadOnlyList RelationshipCategories { get; init; } = []; } public sealed class LocationType { public int LocationTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class LocationRelationshipType { public int LocationRelationshipTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class LocationItem { public int LocationID { get; set; } public int ProjectID { get; set; } public int? ParentLocationID { get; set; } public string? ParentLocationName { get; set; } public string LocationName { get; set; } = string.Empty; public int? LocationTypeID { get; set; } public string? LocationTypeName { get; set; } public string? Description { get; set; } public string LocationPath { get; set; } = string.Empty; public int Depth { get; set; } public bool ShowInQuickAddBar { get; set; } public bool ExcludeFromCompanionDetection { get; set; } public int DetectionPriority { get; set; } = 50; public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } } public sealed class LocationRelationship { public int LocationRelationshipID { get; set; } public int FromLocationID { get; set; } public string FromLocationName { get; set; } = string.Empty; public int ToLocationID { get; set; } public string ToLocationName { get; set; } = string.Empty; public int LocationRelationshipTypeID { get; set; } public string RelationshipTypeName { get; set; } = string.Empty; public bool IsBidirectional { get; set; } public int? Strength { get; set; } public bool CanHearNormalSpeech { get; set; } public bool CanHearLoudNoise { get; set; } public bool CanSeeMovement { get; set; } public bool CanSeeClearly { get; set; } public bool CanTravelDirectly { get; set; } public string? Notes { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } } public static class FloorPlanBlockTypes { public const string Room = "Room"; public const string Corridor = "Corridor"; public const string OpenSpace = "OpenSpace"; public const string Exterior = "Exterior"; public const string Other = "Other"; public static readonly IReadOnlyList All = [Room, Corridor, OpenSpace, Exterior, Other]; public static bool IsValid(string? blockType) => All.Contains(blockType ?? string.Empty, StringComparer.OrdinalIgnoreCase); } public sealed class FloorPlan { public int FloorPlanID { get; set; } public int ProjectID { get; set; } public int? LocationID { get; set; } public string? LocationName { get; set; } public string? LocationPath { get; set; } public string Name { get; set; } = string.Empty; public string? Description { get; set; } public DateTime CreatedDate { get; set; } public DateTime? ModifiedDate { get; set; } public int FloorCount { get; set; } public int BlockCount { get; set; } } public sealed class FloorPlanFloor { public int FloorPlanFloorID { get; set; } public int FloorPlanID { get; set; } public int? LocationID { get; set; } public string? LocationName { get; set; } public string? LocationPath { get; set; } public string Name { get; set; } = string.Empty; public string? Description { get; set; } public int SortOrder { get; set; } public int GridWidth { get; set; } = 24; public int GridHeight { get; set; } = 16; public string? BackgroundImagePath { get; set; } public string? BackgroundImageOriginalFileName { get; set; } public decimal? BackgroundOpacity { get; set; } = 0.35m; public decimal? BackgroundScale { get; set; } = 1m; public decimal? BackgroundOffsetX { get; set; } public decimal? BackgroundOffsetY { get; set; } public bool BackgroundLocked { get; set; } = true; public DateTime CreatedDate { get; set; } public DateTime? ModifiedDate { get; set; } } public sealed class FloorPlanBlock { // Future L-shape support: ShapeType plus FootWidthCells, FootHeightCells, and CornerPosition can extend rectangles without a freeform polygon editor. public int FloorPlanBlockID { get; set; } public int FloorPlanFloorID { get; set; } public int LocationID { get; set; } public string LocationName { get; set; } = string.Empty; public string LocationPath { get; set; } = string.Empty; public int X { get; set; } public int Y { get; set; } public int WidthCells { get; set; } = 1; public int HeightCells { get; set; } = 1; public string BlockType { get; set; } = FloorPlanBlockTypes.Room; public string? LabelOverride { get; set; } public string? Notes { get; set; } public DateTime CreatedDate { get; set; } public DateTime? ModifiedDate { get; set; } public string DisplayLabel => string.IsNullOrWhiteSpace(LabelOverride) ? LocationName : LabelOverride; } public static class FloorPlanTransitionTypes { public const string Door = "Door"; public const string DoubleDoor = "Double Door"; public const string Archway = "Archway"; public const string OpenPassage = "Open Passage"; public const string HiddenPassage = "Hidden Passage"; public const string FrenchDoors = "French Doors"; public const string SlidingDoors = "Sliding Doors"; public const string ExteriorDoor = "Exterior Door"; public const string HiddenDoor = "Hidden Door"; public const string BlockedDoor = "Blocked Door"; public const string StairsUp = "Stairs Up"; public const string StairsDown = "Stairs Down"; public const string Ladder = "Ladder"; public const string SecretPassage = "Secret Passage"; public const string Window = "Window"; public static readonly IReadOnlyList All = [ Door, DoubleDoor, Archway, OpenPassage, HiddenPassage, FrenchDoors, SlidingDoors, ExteriorDoor, HiddenDoor, BlockedDoor, StairsUp, StairsDown, Ladder, SecretPassage, Window ]; public static bool IsValid(string? transitionType) { if (All.Contains(transitionType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { return true; } var normalized = new string((transitionType ?? string.Empty).Where(char.IsLetterOrDigit).Select(char.ToLowerInvariant).ToArray()); return normalized is "frenchdoor" or "slidingdoor" or "ladders"; } } public sealed class SceneFloorPlanOccupancy { public int SceneFloorPlanOccupancyID { get; set; } public int SceneID { get; set; } public int FloorPlanID { get; set; } public int? FloorPlanFloorID { get; set; } public string? FloorName { get; set; } public int? CharacterID { get; set; } public string? CharacterName { get; set; } public string? CharacterShortName { get; set; } public string? CharacterImagePath { get; set; } public string? CharacterThumbnailPath { get; set; } public int? StoryAssetID { get; set; } public string? AssetName { get; set; } public string? AssetImagePath { get; set; } public string? AssetThumbnailPath { get; set; } public int LocationID { get; set; } public string LocationName { get; set; } = string.Empty; public string LocationPath { get; set; } = string.Empty; public DateTime CreatedDate { get; set; } public DateTime? ModifiedDate { get; set; } } public sealed class FloorPlanOccupancyParticipant { public int SceneID { get; set; } public string EntityType { get; set; } = string.Empty; public int EntityID { get; set; } public string DisplayName { get; set; } = string.Empty; } public static class FloorPlanTransitionPositions { public const string Centre = "Centre"; public const string North = "North"; public const string South = "South"; public const string East = "East"; public const string West = "West"; public const string NorthWest = "North West"; public const string NorthEast = "North East"; public const string SouthWest = "South West"; public const string SouthEast = "South East"; public static readonly IReadOnlyList All = [ Centre, North, South, East, West, NorthWest, NorthEast, SouthWest, SouthEast ]; public static bool IsValid(string? position) => All.Contains(position ?? string.Empty, StringComparer.OrdinalIgnoreCase); } public sealed class FloorPlanTransition { public int FloorPlanTransitionID { get; set; } public int FloorPlanFloorID { get; set; } public int FromLocationID { get; set; } public string FromLocationName { get; set; } = string.Empty; public string FromLocationPath { get; set; } = string.Empty; public int ToLocationID { get; set; } public string ToLocationName { get; set; } = string.Empty; public string ToLocationPath { get; set; } = string.Empty; public string TransitionType { get; set; } = FloorPlanTransitionTypes.Door; public string? Notes { get; set; } public bool IsLocked { get; set; } public string? DisplayLabel { get; set; } public string PositionWithinLocation { get; set; } = FloorPlanTransitionPositions.Centre; public DateTime CreatedDate { get; set; } public DateTime? ModifiedDate { get; set; } } public sealed class SceneAssetLocation { public int SceneAssetLocationID { get; set; } public int SceneID { get; set; } public int StoryAssetID { get; set; } public string AssetName { get; set; } = string.Empty; public int LocationID { get; set; } public string LocationName { get; set; } = string.Empty; public string LocationPath { get; set; } = string.Empty; public string? Description { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class LocationLookupData { public IReadOnlyList LocationTypes { get; init; } = []; public IReadOnlyList RelationshipTypes { get; init; } = []; } public sealed class WarningType { public int WarningTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public string? Description { get; set; } public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class WarningSeverity { public int WarningSeverityID { get; set; } public string SeverityName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class ContinuityWarning { public int ContinuityWarningID { get; set; } public int? ValidationRunID { get; set; } public int ProjectID { get; set; } public int? BookID { get; set; } public string? BookTitle { get; set; } public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int? ChapterID { get; set; } public decimal? ChapterNumber { get; set; } public string? ChapterTitle { get; set; } public int? SceneID { get; set; } public decimal? SceneNumber { get; set; } public string? SceneTitle { get; set; } public string EntityType { get; set; } = string.Empty; public int? EntityID { get; set; } public int WarningTypeID { get; set; } public string WarningTypeName { get; set; } = string.Empty; public int WarningSeverityID { get; set; } public string SeverityName { get; set; } = string.Empty; public string Message { get; set; } = string.Empty; public string? Details { get; set; } public bool IsDismissed { get; set; } public bool IsIntentional { get; set; } public DateTime CreatedDate { get; set; } public DateTime LastDetectedDate { get; set; } } public sealed class ContinuityWarningAcknowledgement { public int ContinuityWarningAcknowledgementID { get; set; } public int ProjectID { get; set; } public string WarningType { get; set; } = string.Empty; public int? SceneID { get; set; } public int? CharacterID { get; set; } public int? AssetID { get; set; } public DateTime AcknowledgedDate { get; set; } public int? AcknowledgedByUserID { get; set; } public string? Notes { get; set; } } public sealed class WarningLookupData { public IReadOnlyList WarningTypes { get; init; } = []; public IReadOnlyList Severities { get; init; } = []; } public sealed class ContinuityValidationSummary { public int ValidationRunID { get; set; } public int ErrorCount { get; set; } public int WarningCount { get; set; } public int InfoCount { get; set; } public int TotalCount { get; set; } } public sealed class SceneWarningCount { public int SceneID { get; set; } public int WarningCount { get; set; } } public sealed class SceneDependencyType { public int SceneDependencyTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class SceneDependency { public int SceneDependencyID { get; set; } public int ProjectID { get; set; } public int SourceSceneID { get; set; } public int TargetSceneID { get; set; } public int SceneDependencyTypeID { get; set; } public string SceneDependencyTypeName { get; set; } = string.Empty; public string? Description { get; set; } public bool IsHardDependency { get; set; } public string? DependencyDirection { get; set; } public int SourceBookID { get; set; } public string SourceBookTitle { get; set; } = string.Empty; public string? SourceBookSubtitle { get; set; } public string SourceBookDisplayTitle => BookTitleFormatter.DisplayTitle(SourceBookTitle, SourceBookSubtitle); public int SourceChapterID { get; set; } public decimal SourceChapterNumber { get; set; } public decimal SourceSceneNumber { get; set; } public string SourceSceneTitle { get; set; } = string.Empty; public int TargetBookID { get; set; } public string TargetBookTitle { get; set; } = string.Empty; public string? TargetBookSubtitle { get; set; } public string TargetBookDisplayTitle => BookTitleFormatter.DisplayTitle(TargetBookTitle, TargetBookSubtitle); public int TargetChapterID { get; set; } public decimal TargetChapterNumber { get; set; } public decimal TargetSceneNumber { get; set; } public string TargetSceneTitle { get; set; } = string.Empty; public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public bool IsArchived { get; set; } } public sealed class SceneDependencyLookupData { public IReadOnlyList DependencyTypes { get; init; } = []; } public sealed class SceneDependencyCount { public int SceneID { get; set; } public int DependencyCount { get; set; } } public sealed class ChapterOption { public int ChapterID { get; set; } public int BookID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int BookNumber { get; set; } public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; } public sealed class SceneMovePreview { public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public int SourceChapterID { get; set; } public decimal SourceChapterNumber { get; set; } public string SourceChapterTitle { get; set; } = string.Empty; public int SourceBookID { get; set; } public string SourceBookTitle { get; set; } = string.Empty; public string? SourceBookSubtitle { get; set; } public string SourceBookDisplayTitle => BookTitleFormatter.DisplayTitle(SourceBookTitle, SourceBookSubtitle); public int TargetChapterID { get; set; } public decimal TargetChapterNumber { get; set; } public string TargetChapterTitle { get; set; } = string.Empty; public int TargetBookID { get; set; } public string TargetBookTitle { get; set; } = string.Empty; public string? TargetBookSubtitle { get; set; } public string TargetBookDisplayTitle => BookTitleFormatter.DisplayTitle(TargetBookTitle, TargetBookSubtitle); public string Position { get; set; } = "End"; public int DependencyCount { get; set; } public int ActiveWarningCount { get; set; } } public sealed class AnalyticsMetricPoint { public int SceneID { get; set; } public int BookID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int ChapterID { get; set; } public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public int GlobalSceneIndex { get; set; } public int BookSceneIndex { get; set; } public int MetricTypeID { get; set; } public string MetricName { get; set; } = string.Empty; public int Value { get; set; } public int MinValue { get; set; } public int MaxValue { get; set; } public int Percent { get; set; } } public sealed class AnalyticsRevisionSummary { public int RevisionStatusID { get; set; } public string StatusName { get; set; } = string.Empty; public int SceneCount { get; set; } public int ChapterCount { get; set; } } public sealed class AnalyticsRevisionScene { public int SceneID { get; set; } public int BookID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int ChapterID { get; set; } public decimal ChapterNumber { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public string RevisionStatusName { get; set; } = string.Empty; } public sealed class AnalyticsPurposeSummary { public int ScenePurposeTypeID { get; set; } public string PurposeName { get; set; } = string.Empty; public int SceneCount { get; set; } public decimal PercentOfScenes { get; set; } } public sealed class AnalyticsSceneGap { public int SceneID { get; set; } public int BookID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int ChapterID { get; set; } public decimal ChapterNumber { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public bool MissingPurpose { get; set; } public bool MissingOutcome { get; set; } } public sealed class AnalyticsThreadHealth { public int PlotThreadID { get; set; } public string ThreadTitle { get; set; } = string.Empty; public int PlotLineID { get; set; } public string PlotLineName { get; set; } = string.Empty; public int Importance { get; set; } public string ThreadStatusName { get; set; } = string.Empty; public bool IsOpenStatus { get; set; } public bool IsResolvedStatus { get; set; } public int? IntroducedSceneID { get; set; } public int? PlannedResolutionSceneID { get; set; } public int? ActualResolutionSceneID { get; set; } public int? LastTouchedSceneID { get; set; } public string? LastTouchedSceneLabel { get; set; } public bool IsHighImportanceOpen { get; set; } public bool IsDormant { get; set; } public bool HasClueWithoutPayoff { get; set; } public bool HasQuestionWithoutAnswer { get; set; } } public sealed class AnalyticsAssetHealth { public int StoryAssetID { get; set; } public string AssetName { get; set; } = string.Empty; public string KindName { get; set; } = string.Empty; public int Importance { get; set; } public int? CurrentStateID { get; set; } public string? CurrentStateName { get; set; } public int? CurrentLocationID { get; set; } public string? CurrentLocationPath { get; set; } public bool IsResolved { get; set; } public int? LastEventSceneID { get; set; } public string? LastEventSceneLabel { get; set; } public bool HasDependencies { get; set; } public bool HasDependencyWarnings { get; set; } } public sealed class AnalyticsWarningSeverityCount { public string SeverityName { get; set; } = string.Empty; public int WarningCount { get; set; } } public sealed class AnalyticsWarningTypeCount { public string WarningTypeName { get; set; } = string.Empty; public int WarningCount { get; set; } } public sealed class AnalyticsWarningHotspot { public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public decimal ChapterNumber { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int WarningCount { get; set; } public int HighestSeveritySort { get; set; } } public sealed class AnalyticsPovSummary { public string POVName { get; set; } = string.Empty; public int? POVCharacterID { get; set; } public int SceneCount { get; set; } } public sealed class AnalyticsMultiPovChapter { public int ChapterID { get; set; } public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public int POVCount { get; set; } } public sealed class AnalyticsCharacterAppearance { public int CharacterID { get; set; } public string CharacterName { get; set; } = string.Empty; public int SceneCount { get; set; } } public sealed class StoryBibleCharacterSummary { public int CharacterID { get; set; } public string CharacterName { get; set; } = string.Empty; public string? ShortName { get; set; } public string? Description { get; set; } public string? EyeColour { get; set; } public string? Height { get; set; } public int? AgeAtSeriesStart { get; set; } public int SceneCount { get; set; } public int PovSceneCount { get; set; } public int KnowledgeCount { get; set; } public int RelationshipCount { get; set; } public int MissingLocationCount { get; set; } public int? FirstSceneID { get; set; } public string? FirstSceneLabel { get; set; } public int? LastSceneID { get; set; } public string? LastSceneLabel { get; set; } public string? LocationHistory { get; set; } } public sealed class StoryBibleThreadSummary { public int PlotThreadID { get; set; } public string ThreadTitle { get; set; } = string.Empty; public string PlotLineName { get; set; } = string.Empty; public string ThreadTypeName { get; set; } = string.Empty; public string ThreadStatusName { get; set; } = string.Empty; public int Importance { get; set; } public int EventCount { get; set; } public int? IntroducedSceneID { get; set; } public string? IntroducedSceneLabel { get; set; } public int? LastTouchedSceneID { get; set; } public string? LastTouchedSceneLabel { get; set; } public int? PlannedResolutionSceneID { get; set; } public string? PlannedResolutionSceneLabel { get; set; } public int? ActualResolutionSceneID { get; set; } public string? ActualResolutionSceneLabel { get; set; } public string? EventHistory { get; set; } public int WarningCount { get; set; } } public sealed class StoryBibleAssetSummary { public int StoryAssetID { get; set; } public string AssetName { get; set; } = string.Empty; public string KindName { get; set; } = string.Empty; public int Importance { get; set; } public string? CurrentStateName { get; set; } public string? CurrentLocationPath { get; set; } public bool IsResolved { get; set; } public int EventCount { get; set; } public int DependencyCount { get; set; } public int CustodyCount { get; set; } public int SceneCount { get; set; } public string? EventHistory { get; set; } public string? DependencySummary { get; set; } public string? CustodySummary { get; set; } public int WarningCount { get; set; } } public sealed class StoryBibleRelationshipSummary { public int CharacterRelationshipID { get; set; } public int CharacterAID { get; set; } public string CharacterAName { get; set; } = string.Empty; public int CharacterBID { get; set; } public string CharacterBName { get; set; } = string.Empty; public string RelationshipTypeName { get; set; } = string.Empty; public int RelationshipCategoryID { get; set; } public string RelationshipCategoryName { get; set; } = "Other"; public int CategorySortOrder { get; set; } public int RelationshipTypeSortOrder { get; set; } public string? InitialRelationshipName { get; set; } public string? InitialStateName { get; set; } public int? InitialIntensity { get; set; } public string? CurrentStateName { get; set; } public int? CurrentIntensity { get; set; } public int EventCount { get; set; } public string? FirstEventLabel { get; set; } public string? EventHistory { get; set; } } public sealed class StoryBibleLocationSummary { public int LocationID { get; set; } public string LocationName { get; set; } = string.Empty; public string LocationPath { get; set; } = string.Empty; public string? LocationTypeName { get; set; } public int SceneCount { get; set; } public int CharacterCount { get; set; } public int AssetCount { get; set; } public int RelationshipCount { get; set; } public string? RelatedLocations { get; set; } } public sealed class StoryBibleTimelineSummary { public int BookID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int ChapterID { get; set; } public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public string? Summary { get; set; } public string? PovCharacterName { get; set; } public string? LocationPath { get; set; } public string RevisionStatusName { get; set; } = string.Empty; } public sealed class StoryBibleAttentionItem { public string Category { get; set; } = string.Empty; public string SeverityName { get; set; } = "Info"; public string Title { get; set; } = string.Empty; public string? Detail { get; set; } public int? SceneID { get; set; } public int? EntityID { get; set; } public string? EntityType { get; set; } } public sealed class StoryBibleRevisionItem { public string GroupName { get; set; } = string.Empty; public int ItemCount { get; set; } public string? Detail { get; set; } public int? SceneID { get; set; } public int? ChapterID { get; set; } } public sealed class StoryBibleSearchResult { public string ResultType { get; set; } = string.Empty; public int EntityID { get; set; } public string Title { get; set; } = string.Empty; public string? Detail { get; set; } public int? SceneID { get; set; } } public sealed class SceneNoteType { public int SceneNoteTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class SceneNote { public int SceneNoteID { get; set; } public int SceneID { get; set; } public int SceneNoteTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public string? NoteTitle { get; set; } public string NoteText { get; set; } = string.Empty; public int? SortOrder { get; set; } public bool IsPinned { get; set; } public bool IsResolved { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class ChapterGoal { public int ChapterGoalID { get; set; } public int ChapterID { get; set; } public string? GoalSummary { get; set; } public string? EmotionalGoal { get; set; } public string? ReaderTakeaway { get; set; } public string? MustInclude { get; set; } public string? RisksOrConcerns { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class SceneWorkflow { public int SceneWorkflowID { get; set; } public int SceneID { get; set; } public string DraftStatus { get; set; } = "Planned"; public int? EstimatedWordCount { get; set; } public int? ActualWordCount { get; set; } public DateTime? DraftedDate { get; set; } public DateTime? LastWorkedOn { get; set; } public bool ReadyForDraft { get; set; } public bool ReadyForRevision { get; set; } public bool ReadyForPolish { get; set; } public bool IsBlocked { get; set; } public string? BlockedReason { get; set; } public int? Priority { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class SceneChecklistItem { public int SceneChecklistItemID { get; set; } public int SceneID { get; set; } public string ItemText { get; set; } = string.Empty; public bool IsCompleted { get; set; } public int? SortOrder { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class SceneAttachmentType { public int SceneAttachmentTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public int SortOrder { get; set; } public bool IsActive { get; set; } } public sealed class SceneAttachment { public int SceneAttachmentID { get; set; } public int SceneID { get; set; } public int SceneAttachmentTypeID { get; set; } public string TypeName { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public string? FilePath { get; set; } public string? ExternalUrl { get; set; } public string? Notes { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class WriterDashboardScene { public int ProjectID { get; set; } public string ProjectName { get; set; } = string.Empty; public int BookID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int ChapterID { get; set; } public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public string? Summary { get; set; } public int RevisionStatusID { get; set; } public string RevisionStatusName { get; set; } = string.Empty; public string DraftStatus { get; set; } = "Planned"; public int? Priority { get; set; } public bool IsBlocked { get; set; } public string? BlockedReason { get; set; } public int WarningCount { get; set; } public int RemainingChecklistCount { get; set; } public int UnresolvedNoteCount { get; set; } public string? ImportantThreads { get; set; } public string? PinnedNotes { get; set; } } public sealed class WritingPlan { public int WritingPlanID { get; set; } public int UserID { get; set; } public int ProjectID { get; set; } public int? BookID { get; set; } public string PlanName { get; set; } = string.Empty; public string GoalType { get; set; } = string.Empty; public DateTime StartDate { get; set; } public DateTime DeadlineDate { get; set; } public string AvailableDaysJson { get; set; } = string.Empty; public int SessionLengthMinutes { get; set; } public bool IncludeBlockedScenes { get; set; } public string RebalanceMode { get; set; } = "Ask"; public bool IsActive { get; set; } = true; public DateTime CreatedDateUtc { get; set; } public DateTime ModifiedDateUtc { get; set; } } public sealed class WritingScheduleItem { public int WritingScheduleItemID { get; set; } public int WritingPlanID { get; set; } public int SceneID { get; set; } public DateTime ScheduledDate { get; set; } public string TaskType { get; set; } = string.Empty; public int? EstimatedMinutes { get; set; } public int? TargetWords { get; set; } public string ScheduleStatus { get; set; } = string.Empty; public DateTime? CompletedDateUtc { get; set; } public string? Notes { get; set; } public DateTime CreatedDateUtc { get; set; } public DateTime ModifiedDateUtc { get; set; } } public sealed class WritingScheduleScene { public int SceneID { get; set; } public string RevisionStatusName { get; set; } = string.Empty; public int? EstimatedWordCount { get; set; } public int? Priority { get; set; } public bool IsBlocked { get; set; } public int BookSortOrder { get; set; } public int ChapterSortOrder { get; set; } public int SceneSortOrder { get; set; } } public sealed class WritingPlanSummary { public int WritingPlanID { get; set; } public int UserID { get; set; } public int ProjectID { get; set; } public string ProjectName { get; set; } = string.Empty; public int? BookID { get; set; } public string? BookTitle { get; set; } public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public string PlanName { get; set; } = string.Empty; public DateTime DeadlineDate { get; set; } public bool IsActive { get; set; } } public sealed class WritingPlanManagementItem { public int WritingPlanID { get; set; } public int UserID { get; set; } public int ProjectID { get; set; } public string ProjectName { get; set; } = string.Empty; public int? BookID { get; set; } public string? BookTitle { get; set; } public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public string PlanName { get; set; } = string.Empty; public string GoalType { get; set; } = string.Empty; public DateTime StartDate { get; set; } public DateTime DeadlineDate { get; set; } public string AvailableDaysJson { get; set; } = string.Empty; public int SessionLengthMinutes { get; set; } public string AvailabilitySummary { get; set; } = string.Empty; public bool IsActive { get; set; } public int PlannedTaskCount { get; set; } public DateTime? ProjectedFinishDate { get; set; } } public sealed class WritingSchedulePreviewItem { public int WritingScheduleItemID { get; set; } public int WritingPlanID { get; set; } public int SceneID { get; set; } public DateTime ScheduledDate { get; set; } public string TaskType { get; set; } = string.Empty; public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public int? Priority { get; set; } public int? EstimatedMinutes { get; set; } public int? TargetWords { get; set; } public string ScheduleStatus { get; set; } = string.Empty; public string? Notes { get; set; } public bool IsBlocked { get; set; } } public sealed class WritingScheduleDashboardItem { public int WritingScheduleItemID { get; set; } public int WritingPlanID { get; set; } public string PlanName { get; set; } = string.Empty; public int SceneID { get; set; } public DateTime ScheduledDate { get; set; } public string TaskType { get; set; } = string.Empty; public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public int ChapterSortOrder { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public int SceneSortOrder { get; set; } public int? Priority { get; set; } public int? EstimatedMinutes { get; set; } public int? TargetWords { get; set; } public string ScheduleStatus { get; set; } = string.Empty; public bool IsBlocked { get; set; } } public sealed class WritingScheduleItemDateChange { public int WritingScheduleItemID { get; set; } public DateTime ScheduledDate { get; set; } } public sealed class ChapterWorkflowScene { public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public int RevisionStatusID { get; set; } public string RevisionStatusName { get; set; } = string.Empty; public string DraftStatus { get; set; } = "Planned"; public int? Priority { get; set; } public bool ReadyForDraft { get; set; } public bool ReadyForRevision { get; set; } public bool ReadyForPolish { get; set; } public bool IsBlocked { get; set; } public string? BlockedReason { get; set; } public int WarningCount { get; set; } public int RemainingChecklistCount { get; set; } public int UnresolvedNoteCount { get; set; } } public sealed class ExportSceneBriefHeader { public int ProjectID { get; set; } public string ProjectName { get; set; } = string.Empty; public int BookID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int ChapterID { get; set; } public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public string? Summary { get; set; } public string? ScenePurposeNotes { get; set; } public string? SceneOutcomeNotes { get; set; } public string RevisionStatusName { get; set; } = string.Empty; public string? PovCharacterName { get; set; } public string? LocationPath { get; set; } public string TimeLabel { get; set; } = string.Empty; public string DraftStatus { get; set; } = "Planned"; public bool IsBlocked { get; set; } public string? BlockedReason { get; set; } public int? Priority { get; set; } } public sealed class ExportBriefItem { public string ItemType { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public string? Detail { get; set; } public string? Status { get; set; } public int? SortOrder { get; set; } } public sealed class ExportChapterBriefHeader { public int ProjectID { get; set; } public string ProjectName { get; set; } = string.Empty; public int BookID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int ChapterID { get; set; } public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public string? Summary { get; set; } public string RevisionStatusName { get; set; } = string.Empty; public string? GoalSummary { get; set; } public string? EmotionalGoal { get; set; } public string? ReaderTakeaway { get; set; } public string? MustInclude { get; set; } public string? RisksOrConcerns { get; set; } } public sealed class ExportResearchItem { public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public string Topic { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public string? Detail { get; set; } public string? Reference { get; set; } } public sealed class ExportPacket { public string Title { get; set; } = string.Empty; public IReadOnlyList Characters { get; init; } = []; public IReadOnlyList PlotThreads { get; init; } = []; public IReadOnlyList Assets { get; init; } = []; public IReadOnlyList Relationships { get; init; } = []; public IReadOnlyList Locations { get; init; } = []; public IReadOnlyList Timeline { get; init; } = []; public IReadOnlyList OpenQuestions { get; init; } = []; public IReadOnlyList RevisionItems { get; init; } = []; public ExportSceneBriefHeader? SceneHeader { get; init; } public ExportChapterBriefHeader? ChapterHeader { get; init; } public Character? Character { get; init; } public IReadOnlyList CharacterAppearances { get; init; } = []; public IReadOnlyList CharacterRelationships { get; init; } = []; public IReadOnlyList CharacterKnowledge { get; init; } = []; public IReadOnlyList CharacterCustody { get; init; } = []; public IReadOnlyList Items { get; init; } = []; public IReadOnlyList ResearchItems { get; init; } = []; public IReadOnlyList SearchResults { get; init; } = []; } public sealed class CharacterArcPoint { public int SceneID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public decimal ChapterNumber { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public int GlobalSceneIndex { get; set; } public bool IsPov { get; set; } public int? EmotionalWeight { get; set; } public int? Tension { get; set; } public int? Romance { get; set; } public int? Action { get; set; } public int? Darkness { get; set; } public int? HopeLightness { get; set; } public int? OverallIntensity { get; set; } public string? RoleInSceneTypeName { get; set; } public string? PresenceTypeName { get; set; } public string? EmotionalState { get; set; } public string? AppearanceNotes { get; set; } public string? KeyNotes { get; set; } } public sealed class RelationshipProgressionPoint { public int RelationshipEventID { get; set; } public int CharacterRelationshipID { get; set; } public int SceneID { get; set; } public string BookTitle { get; set; } = string.Empty; public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public decimal ChapterNumber { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public int GlobalSceneIndex { get; set; } public string RelationshipStateName { get; set; } = string.Empty; public int? Intensity { get; set; } public bool IsKnownToOtherCharacter { get; set; } public string? Description { get; set; } } public sealed class CharacterPairingSummary { public int CharacterAID { get; set; } public string CharacterAName { get; set; } = string.Empty; public int CharacterBID { get; set; } public string CharacterBName { get; set; } = string.Empty; public int SharedSceneCount { get; set; } public string? FirstSceneLabel { get; set; } public string? LastSceneLabel { get; set; } } public sealed class DynamicsIssue { public string Category { get; set; } = string.Empty; public string SeverityName { get; set; } = "Info"; public string Title { get; set; } = string.Empty; public string? Detail { get; set; } public int? SceneID { get; set; } public int? EntityID { get; set; } public string? EntityType { get; set; } } public sealed class Scenario { public int ScenarioID { get; set; } public int ProjectID { get; set; } public int? BookID { get; set; } public string ScenarioName { get; set; } = string.Empty; public string? Description { get; set; } public DateTime BaseCreatedDate { get; set; } public bool IsAppliedToMain { get; set; } public bool IsArchived { get; set; } public DateTime CreatedDate { get; set; } public DateTime UpdatedDate { get; set; } public string ProjectName { get; set; } = string.Empty; public string? BookTitle { get; set; } public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public int SceneCount { get; set; } public int WarningCount { get; set; } } public sealed class ScenarioScene { public int ScenarioSceneOrderID { get; set; } public int ScenarioID { get; set; } public int SceneID { get; set; } public int OriginalChapterID { get; set; } public int ProposedChapterID { get; set; } public int ProposedSortOrder { get; set; } public string? Notes { get; set; } public decimal ChapterNumber { get; set; } public string ChapterTitle { get; set; } = string.Empty; public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public string? Summary { get; set; } public string RevisionStatusName { get; set; } = string.Empty; public string TimeLabel { get; set; } = string.Empty; public string? ThreadLabels { get; set; } public string? AssetLabels { get; set; } public string? CharacterLabels { get; set; } public string? LocationLabel { get; set; } public int WarningCount { get; set; } } public sealed class ScenarioWarning { public int ScenarioWarningID { get; set; } public int ScenarioValidationRunID { get; set; } public int ScenarioID { get; set; } public int? SceneID { get; set; } public string EntityType { get; set; } = string.Empty; public int? EntityID { get; set; } public string WarningTypeName { get; set; } = string.Empty; public string SeverityName { get; set; } = "Info"; public string Message { get; set; } = string.Empty; public string? Details { get; set; } public DateTime CreatedDate { get; set; } } public sealed class ScenarioComparisonRow { public int SceneID { get; set; } public string SceneTitle { get; set; } = string.Empty; public string MainPosition { get; set; } = string.Empty; public string ScenarioPosition { get; set; } = string.Empty; public int MainIndex { get; set; } public int ScenarioIndex { get; set; } public bool HasMoved { get; set; } } public sealed class ArchivedItem { public string EntityType { get; set; } = string.Empty; public int EntityID { get; set; } public string DisplayName { get; set; } = string.Empty; public int? ProjectID { get; set; } public string? ProjectName { get; set; } public int? BookID { get; set; } public string? BookTitle { get; set; } public string? BookSubtitle { get; set; } public string BookDisplayTitle => BookTitleFormatter.DisplayTitle(BookTitle, BookSubtitle); public DateTime? ArchivedDate { get; set; } public string? ArchivedReason { get; set; } public DateTime UpdatedDate { get; set; } } public sealed class ArchiveDeleteResult { public bool Succeeded { get; set; } public string Message { get; set; } = string.Empty; } public sealed class Phase1AcceptanceChecklistItem { public string AreaName { get; set; } = string.Empty; public string CheckName { get; set; } = string.Empty; public string Status { get; set; } = string.Empty; public string Detail { get; set; } = string.Empty; public int SortOrder { get; set; } } public sealed class AnalyticsBusyScene { public int SceneID { get; set; } public decimal SceneNumber { get; set; } public string SceneTitle { get; set; } = string.Empty; public decimal ChapterNumber { get; set; } public int CharacterCount { get; set; } } public sealed class AnalyticsLocationUsage { public string LocationName { get; set; } = string.Empty; public int? LocationID { get; set; } public string LocationPath { get; set; } = string.Empty; public int SceneCount { get; set; } } public sealed class LookupData { public IReadOnlyList RevisionStatuses { get; init; } = []; public IReadOnlyList TimeModes { get; init; } = []; public IReadOnlyList DurationUnits { get; init; } = []; public IReadOnlyList TimeConfidences { get; init; } = []; public IReadOnlyList ScenePurposeTypes { get; init; } = []; public IReadOnlyList ChapterPurposeTypes { get; init; } = []; }