using System.Text.Json; using Tiku.Domain.Common; namespace Tiku.Domain.Content; public sealed class ContentAsset : AuditableTenantEntity { public Guid? RegionId { get; set; } public Guid? SubjectId { get; set; } public Guid? CategoryId { get; set; } public Guid? ContentNodeId { get; set; } public Guid? CreatedBy { get; set; } public Guid? UpdatedBy { get; set; } public Guid? VerifiedBy { get; set; } public string? LegacyId { get; set; } public string? AssetKey { get; set; } public string? Title { get; set; } public string? Category { get; set; } public string? Description { get; set; } public string? FileName { get; set; } public string? CdnUrl { get; set; } public bool IsPublic { get; set; } public ContentAssetType AssetType { get; set; } = ContentAssetType.Document; public AssetStorageProvider StorageProvider { get; set; } = AssetStorageProvider.ExternalUrl; public string? Bucket { get; set; } public string? ObjectKey { get; set; } public string? MimeType { get; set; } public long? FileSizeBytes { get; set; } public string? ChecksumSha256 { get; set; } public ContentVisibility Visibility { get; set; } = ContentVisibility.Members; public string? PreviewUrl { get; set; } public ContentStatus Status { get; set; } = ContentStatus.Active; public int SortOrder { get; set; } public JsonElement AccessRules { get; set; } = JsonDefaults.Object(); public string Source { get; set; } = "manual"; public int DownloadCount { get; set; } public AssetUploadStatus UploadStatus { get; set; } = AssetUploadStatus.NotRequired; public DateTimeOffset? VerifiedAt { get; set; } public long? VerifiedSizeBytes { get; set; } public string? VerifiedChecksumSha256 { get; set; } public JsonElement VerificationDetails { get; set; } = JsonDefaults.Object(); public string? PreviewObjectKey { get; set; } public AssetPreviewStatus PreviewStatus { get; set; } = AssetPreviewStatus.None; public AssetSecurityScanStatus SecurityScanStatus { get; set; } = AssetSecurityScanStatus.NotRequired; public DateTimeOffset? SecurityScannedAt { get; set; } public string? SecurityScanProvider { get; set; } public JsonElement SecurityScanSummary { get; set; } = JsonDefaults.Object(); public JsonElement SecurityFlags { get; set; } = JsonDefaults.Object(); public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public sealed class ContentImportJob : AuditableTenantEntity { public Guid? CreatedBy { get; set; } public Guid? TargetRegionId { get; set; } public Guid? TargetSubjectId { get; set; } public Guid? TargetCategoryId { get; set; } public Guid? TargetContentNodeId { get; set; } public Guid? TargetQuestionBankId { get; set; } public ContentImportType ImportType { get; set; } = ContentImportType.Questions; public ImportSourceFormat SourceFormat { get; set; } = ImportSourceFormat.Json; public ContentImportStatus Status { get; set; } = ContentImportStatus.Preview; public string? SourceName { get; set; } public string? SourceHash { get; set; } public bool DryRun { get; set; } = true; public int TotalCount { get; set; } public int ValidCount { get; set; } public int ErrorCount { get; set; } public int WarningCount { get; set; } public int InsertedCount { get; set; } public int UpdatedCount { get; set; } public int SkippedCount { get; set; } public JsonElement Summary { get; set; } = JsonDefaults.Object(); public JsonElement RawPayload { get; set; } = JsonDefaults.Array(); public JsonElement NormalizedPayload { get; set; } = JsonDefaults.Array(); public string? ErrorMessage { get; set; } public DateTimeOffset? StartedAt { get; set; } public DateTimeOffset? FinishedAt { get; set; } } public sealed class ContentImportItem : AuditableTenantEntity { public Guid JobId { get; set; } public int RowNo { get; set; } public string? ExternalId { get; set; } public ContentImportItemStatus Status { get; set; } = ContentImportItemStatus.Valid; public string? TargetType { get; set; } public Guid? TargetId { get; set; } public JsonElement SourcePayload { get; set; } = JsonDefaults.Object(); public JsonElement NormalizedPayload { get; set; } = JsonDefaults.Object(); public string? ContentHash { get; set; } public int IssuesCount { get; set; } } public sealed class ContentImportIssue : AuditableTenantEntity { public Guid JobId { get; set; } public Guid? ItemId { get; set; } public int? RowNo { get; set; } public ImportIssueSeverity Severity { get; set; } = ImportIssueSeverity.Error; public string Code { get; set; } = string.Empty; public string? FieldPath { get; set; } public string Message { get; set; } = string.Empty; public JsonElement Details { get; set; } = JsonDefaults.Object(); } public sealed class ImageAsset : AuditableTenantEntity { public string? LegacyId { get; set; } public string? Title { get; set; } public string? Category { get; set; } public string? FileName { get; set; } public bool IsPublic { get; set; } public string? CdnUrl { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public sealed class AppAsset : AuditableTenantEntity { public string? LegacyId { get; set; } public string AssetKey { get; set; } = string.Empty; public string? FileName { get; set; } public string? Description { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public sealed class VideoExplanation : AuditableTenantEntity { public Guid? SubjectId { get; set; } public string? LegacyId { get; set; } public string? LegacySubjectId { get; set; } public string Title { get; set; } = string.Empty; public string? Description { get; set; } public string? VideoUrl { get; set; } public string? ThumbnailUrl { get; set; } public int? DurationSeconds { get; set; } public JsonElement KnowledgeTags { get; set; } = JsonDefaults.Array(); public bool IsGeneral { get; set; } public int? Difficulty { get; set; } public int SortOrder { get; set; } public bool IsActive { get; set; } = true; public string? SourceHash { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public sealed class QuestionVideo : AuditableTenantEntity { public Guid? QuestionId { get; set; } public Guid? VideoId { get; set; } public string? LegacyId { get; set; } public string? LegacyQuestionId { get; set; } public string? LegacyVideoId { get; set; } public QuestionVideoType VideoType { get; set; } = QuestionVideoType.Specific; public int SortOrder { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public enum ContentAssetType { Pdf, Video, Image, Audio, Document, Package, Link, Other } public enum AssetStorageProvider { ExternalUrl, SupabaseStorage, AliyunOss, TencentCos, QiniuKodo, LocalDev } public enum AssetUploadStatus { NotRequired, Pending, Verified, Failed } public enum AssetPreviewStatus { None, Pending, Ready, Failed } public enum AssetSecurityScanStatus { NotRequired, Pending, Scanning, Passed, Failed, Skipped } public enum ContentImportType { Questions, Vocabulary, Handbook, Scoreline, Assets, Videos } public enum ImportSourceFormat { Json, Excel, Csv, Pocketbase, Api } public enum ContentImportStatus { Preview, Pending, Importing, Completed, CompletedWithErrors, Failed, Rejected } public enum ContentImportItemStatus { Valid, Invalid, Inserted, Updated, Skipped, Failed } public enum ImportIssueSeverity { Error, Warning } public enum QuestionVideoType { Specific, General, Related }