using System.Text.Json; namespace PlotLine.Models; public static class WholeBookPlotSynthesisStatuses { public const string Queued = "Queued"; public const string Running = "Running"; public const string Completed = "Completed"; public const string Failed = "Failed"; public const string Superseded = "Superseded"; } public static class WholeBookPlotSynthesisSources { public const string Author = "Author"; public const string WholeBook = "WholeBookPlotSynthesis"; public const string SceneSignals = "SceneSignals"; } public sealed class AuthorPlotSeed { public int AuthorPlotSeedID { get; set; } public int ProjectID { get; set; } public int BookID { get; set; } public string Description { get; set; } = string.Empty; public string Status { get; set; } = "Active"; public int? MatchedPlotLineID { get; set; } public string Source { get; set; } = WholeBookPlotSynthesisSources.Author; public DateTime CreatedUtc { get; set; } public DateTime UpdatedUtc { get; set; } } public sealed class AuthorPlotSeedSaveRequest { public int ProjectID { get; init; } public int BookID { get; init; } public IReadOnlyList Descriptions { get; init; } = []; } public sealed class WholeBookPlotSynthesisRun { public int WholeBookPlotSynthesisRunID { get; set; } public int ProjectID { get; set; } public int BookID { get; set; } public int UserID { get; set; } public int? SourceStoryIntelligenceRunID { get; set; } public string CharacterResolutionVersion { get; set; } = string.Empty; public string Status { get; set; } = WholeBookPlotSynthesisStatuses.Queued; public DateTime QueuedUtc { get; set; } public DateTime? StartedUtc { get; set; } public DateTime? CompletedUtc { get; set; } public DateTime? FailedUtc { get; set; } public int AttemptCount { get; set; } public string? Model { get; set; } public string? OpenAIResponseID { get; set; } public int? InputTokens { get; set; } public int? OutputTokens { get; set; } public int? CachedInputTokens { get; set; } public int? TotalTokens { get; set; } public long? DurationMs { get; set; } public string? ErrorMessage { get; set; } public string? ErrorDetail { get; set; } public string? ResultJson { get; set; } public DateTime UpdatedUtc { get; set; } } public sealed class WholeBookPlotSynthesisQueueRequest { public int ProjectID { get; init; } public int BookID { get; init; } public int UserID { get; init; } public int? SourceStoryIntelligenceRunID { get; init; } public string CharacterResolutionVersion { get; init; } = string.Empty; } public sealed class WholeBookPlotSynthesisCompletionRequest { public int WholeBookPlotSynthesisRunID { get; init; } public string Model { get; init; } = string.Empty; public string? OpenAIResponseID { get; init; } public int? InputTokens { get; init; } public int? OutputTokens { get; init; } public int? CachedInputTokens { get; init; } public int? TotalTokens { get; init; } public long? DurationMs { get; init; } public string ResultJson { get; init; } = string.Empty; } public sealed class WholeBookPlotSynthesisContext { public int ProjectID { get; init; } public int BookID { get; init; } public string BookTitle { get; init; } = string.Empty; public IReadOnlyList Chapters { get; init; } = []; public IReadOnlyList Characters { get; init; } = []; public IReadOnlyList ExistingPlotLines { get; init; } = []; public IReadOnlyList AuthorSeeds { get; init; } = []; public WholeBookPlotSynthesisSourceAudit SourceAudit { get; init; } = new(); } public sealed class WholeBookPlotSynthesisSourceAudit { public int SceneCount { get; init; } public int SourceRowCount { get; init; } public int MissingSourceCount { get; init; } public int DuplicateSourceSceneCount { get; init; } public bool CanReconstruct => SceneCount > 0 && SceneCount == SourceRowCount && MissingSourceCount == 0 && DuplicateSourceSceneCount == 0; } public sealed class WholeBookPlotSynthesisChapter { public int ChapterID { get; init; } public decimal ChapterNumber { get; init; } public string ChapterTitle { get; init; } = string.Empty; public IReadOnlyList Scenes { get; init; } = []; } public sealed class WholeBookPlotSynthesisScene { public int SceneID { get; init; } public decimal SceneNumber { get; init; } public string SceneTitle { get; init; } = string.Empty; public string? StructuralSummary { get; init; } public string? StructuralSetting { get; init; } public string? PovCharacterName { get; init; } public string SourceText { get; init; } = string.Empty; } public sealed class WholeBookPlotSynthesisCharacter { public int CharacterID { get; init; } public string CanonicalName { get; init; } = string.Empty; public IReadOnlyList Aliases { get; init; } = []; } public sealed class WholeBookPlotSynthesisExistingPlotLine { public int PlotLineID { get; init; } public string Name { get; init; } = string.Empty; public string? Description { get; init; } public string? Importance { get; init; } public int? BookID { get; init; } public IReadOnlyList Threads { get; init; } = []; } public sealed class WholeBookPlotSynthesisExistingThread { public int PlotThreadID { get; init; } public string Title { get; init; } = string.Empty; public string? Summary { get; init; } public string? Status { get; init; } } public sealed class WholeBookPlotSynthesisResult { public WholeBookPlotSynthesisMetadata Metadata { get; init; } = new(); public IReadOnlyList PlotLines { get; init; } = []; public static WholeBookPlotSynthesisResult FromJson(string json) => JsonSerializer.Deserialize( json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? new(); } public sealed class WholeBookPlotSynthesisMetadata { public string BookStatus { get; init; } = string.Empty; public string Summary { get; init; } = string.Empty; } public sealed class WholeBookPlotSynthesisPlotLineResult { public string Key { get; init; } = string.Empty; public string ProposedTitle { get; init; } = string.Empty; public string Description { get; init; } = string.Empty; public string Significance { get; init; } = string.Empty; public string BookStatus { get; init; } = string.Empty; public int? ExistingPlotLineID { get; init; } public decimal? ExistingPlotLineMatchConfidence { get; init; } public string? ExistingPlotLineMatchReason { get; init; } public int? AuthorPlotSeedID { get; init; } public decimal? SeedMatchConfidence { get; init; } public string? SeedMatchReason { get; init; } public decimal? Confidence { get; init; } public IReadOnlyList Threads { get; init; } = []; } public sealed class WholeBookPlotSynthesisThreadResult { public string Key { get; init; } = string.Empty; public string ProposedTitle { get; init; } = string.Empty; public string Description { get; init; } = string.Empty; public string Status { get; init; } = string.Empty; public int? ExistingPlotThreadID { get; init; } public decimal? ExistingThreadMatchConfidence { get; init; } public string? MatchReason { get; init; } public decimal? Confidence { get; init; } public IReadOnlyList Events { get; init; } = []; } public sealed class WholeBookPlotSynthesisEventResult { public string Key { get; init; } = string.Empty; public int SceneID { get; init; } public string EventType { get; init; } = string.Empty; public string Title { get; init; } = string.Empty; public string Description { get; init; } = string.Empty; public string Evidence { get; init; } = string.Empty; public decimal? Confidence { get; init; } }