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<string> 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<int> SelectedPurposeTypeIds { get; set; } = [];
    public List<ScenePurposeLabel> PurposeLabels { get; set; } = [];
    public List<SceneMetricValue> 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<int> 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<PlotLineType> PlotLineTypes { get; init; } = [];
    public IReadOnlyList<PlotImportance> PlotImportance { get; init; } = [];
    public IReadOnlyList<ThreadType> ThreadTypes { get; init; } = [];
    public IReadOnlyList<ThreadStatus> ThreadStatuses { get; init; } = [];
    public IReadOnlyList<ThreadEventType> ThreadEventTypes { get; init; } = [];
    public IReadOnlyList<PlotEventType> 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<AssetKind> AssetKinds { get; init; } = [];
    public IReadOnlyList<AssetState> AssetStates { get; init; } = [];
    public IReadOnlyList<AssetEventType> AssetEventTypes { get; init; } = [];
    public IReadOnlyList<AssetDependencyType> AssetDependencyTypes { get; init; } = [];
    public IReadOnlyList<AssetCustodyEventType> AssetCustodyEventTypes { get; init; } = [];
    public IReadOnlyList<CustodyRole> 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<CharacterRoleInSceneType> RoleTypes { get; init; } = [];
    public IReadOnlyList<PresenceType> PresenceTypes { get; init; } = [];
    public IReadOnlyList<CharacterAttributeType> AttributeTypes { get; init; } = [];
    public IReadOnlyList<KnowledgeState> KnowledgeStates { get; init; } = [];
    public IReadOnlyList<RelationshipType> RelationshipTypes { get; init; } = [];
    public IReadOnlyList<RelationshipState> RelationshipStates { get; init; } = [];
    public IReadOnlyList<RelationshipCategory> RelationshipCategories { get; init; } = [];
}

public sealed class RelationshipMapData
{
    public IReadOnlyList<Character> Characters { get; init; } = [];
    public IReadOnlyList<Book> Books { get; init; } = [];
    public IReadOnlyList<Chapter> Chapters { get; init; } = [];
    public IReadOnlyList<Scene> Scenes { get; init; } = [];
    public IReadOnlyList<CharacterRelationship> Relationships { get; init; } = [];
    public IReadOnlyList<RelationshipEvent> RelationshipEvents { get; init; } = [];
    public IReadOnlyList<RelationshipCategory> 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<string> 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<string> 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<string> 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<LocationType> LocationTypes { get; init; } = [];
    public IReadOnlyList<LocationRelationshipType> 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<WarningType> WarningTypes { get; init; } = [];
    public IReadOnlyList<WarningSeverity> 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<SceneDependencyType> 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<StoryBibleCharacterSummary> Characters { get; init; } = [];
    public IReadOnlyList<StoryBibleThreadSummary> PlotThreads { get; init; } = [];
    public IReadOnlyList<StoryBibleAssetSummary> Assets { get; init; } = [];
    public IReadOnlyList<StoryBibleRelationshipSummary> Relationships { get; init; } = [];
    public IReadOnlyList<StoryBibleLocationSummary> Locations { get; init; } = [];
    public IReadOnlyList<StoryBibleTimelineSummary> Timeline { get; init; } = [];
    public IReadOnlyList<StoryBibleAttentionItem> OpenQuestions { get; init; } = [];
    public IReadOnlyList<StoryBibleRevisionItem> RevisionItems { get; init; } = [];
    public ExportSceneBriefHeader? SceneHeader { get; init; }
    public ExportChapterBriefHeader? ChapterHeader { get; init; }
    public Character? Character { get; init; }
    public IReadOnlyList<SceneCharacter> CharacterAppearances { get; init; } = [];
    public IReadOnlyList<CharacterRelationship> CharacterRelationships { get; init; } = [];
    public IReadOnlyList<CharacterKnowledgeItem> CharacterKnowledge { get; init; } = [];
    public IReadOnlyList<AssetCustodyEvent> CharacterCustody { get; init; } = [];
    public IReadOnlyList<ExportBriefItem> Items { get; init; } = [];
    public IReadOnlyList<ExportResearchItem> ResearchItems { get; init; } = [];
    public IReadOnlyList<StoryBibleSearchResult> 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<RevisionStatus> RevisionStatuses { get; init; } = [];
    public IReadOnlyList<TimeMode> TimeModes { get; init; } = [];
    public IReadOnlyList<DurationUnit> DurationUnits { get; init; } = [];
    public IReadOnlyList<TimeConfidence> TimeConfidences { get; init; } = [];
    public IReadOnlyList<ScenePurposeType> ScenePurposeTypes { get; init; } = [];
    public IReadOnlyList<ChapterPurposeType> ChapterPurposeTypes { get; init; } = [];
}
