using System.Text.Json; using Tiku.Domain.Common; namespace Tiku.Domain.Learning; public sealed class PracticeSession : TenantEntity { public Guid UserId { get; set; } public Guid? BlueprintId { get; set; } public Guid? CollectionId { get; set; } public Guid? EntryId { get; set; } public Guid? ContentNodeId { get; set; } public string Mode { get; set; } = "chapter"; public string? TargetType { get; set; } public Guid? TargetId { get; set; } public DateTimeOffset StartedAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset? FinishedAt { get; set; } public int QuestionCount { get; set; } public int? DurationMinutes { get; set; } public decimal? TotalScore { get; set; } public DateTimeOffset? ExpiresAt { get; set; } public PracticeSessionStatus Status { get; set; } = PracticeSessionStatus.Active; public long Version { get; set; } = 1; public long LastClientSequence { get; set; } public PracticeAccessMode AccessMode { get; set; } = PracticeAccessMode.Free; public Guid? AccessEntitlementId { get; set; } public int ConsumedFreeQuota { get; set; } public JsonElement AccessSnapshot { get; set; } = JsonDefaults.Object(); public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public sealed class PracticeSessionQuestion : TenantEntity { public Guid PracticeSessionId { get; set; } public Guid QuestionReferenceId { get; set; } public Guid QuestionOwnerTenantId { get; set; } public Guid QuestionId { get; set; } public Guid QuestionVersionId { get; set; } public int Position { get; set; } public decimal? Score { get; set; } public string QuestionType { get; set; } = "choice"; public string? TypeLabelSnapshot { get; set; } public int? DifficultySnapshot { get; set; } public JsonElement TagsSnapshot { get; set; } = JsonDefaults.Array(); public string? ContentSnapshot { get; set; } public JsonElement OptionsSnapshot { get; set; } = JsonDefaults.Array(); public int? CorrectOptionIndexSnapshot { get; set; } public JsonElement CorrectOptionIndicesSnapshot { get; set; } = JsonDefaults.Array(); public string? AnswerTextSnapshot { get; set; } public string? ExplanationSnapshot { get; set; } public JsonElement GradingRulesSnapshot { get; set; } = JsonDefaults.Object(); public int SnapshotVersion { get; set; } = 1; } public enum PracticeSessionStatus { Active, Scoring, PendingReview, Submitted, Expired, Cancelled } public enum PracticeAccessMode { Free, Svip, Staff } public sealed class AnswerRecord : TenantEntity { public Guid UserId { get; set; } public Guid PracticeSessionId { get; set; } public Guid SessionQuestionId { get; set; } public string? LegacyId { get; set; } public string? LegacyQuestionId { get; set; } public string? LegacyCategoryId { get; set; } public JsonElement SelectedOptions { get; set; } = JsonDefaults.Array(); public string? AnswerText { get; set; } public bool? IsCorrect { get; set; } public AnswerGradingStatus GradingStatus { get; set; } = AnswerGradingStatus.PendingReview; public decimal? AwardedScore { get; set; } public int Revision { get; set; } = 1; public long ClientSequence { get; set; } public string IdempotencyKey { get; set; } = string.Empty; public string RequestHash { get; set; } = string.Empty; public bool IsCurrent { get; set; } = true; public DateTimeOffset AnsweredAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; } public enum AnswerGradingStatus { PendingReview, Correct, Incorrect, LegacyUnverified } public sealed class LearningOperationIdempotency : Entity, ITenantOwned { public Guid UserId { get; set; } public Guid PracticeSessionId { get; set; } public string OperationType { get; set; } = string.Empty; public string IdempotencyKey { get; set; } = string.Empty; public string RequestHash { get; set; } = string.Empty; public JsonElement ResponseSnapshot { get; set; } = JsonDefaults.Object(); public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset? CompletedAt { get; set; } public Guid TenantId { get; set; } } public sealed class FavoriteQuestion : ITenantOwned { public Guid UserId { get; set; } public Guid QuestionReferenceId { get; set; } public Guid QuestionOwnerTenantId { get; set; } public Guid QuestionId { get; set; } public string Source { get; set; } = "imported"; public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; public Guid TenantId { get; set; } } public sealed class WrongQuestion : ITenantOwned { public Guid UserId { get; set; } public Guid QuestionReferenceId { get; set; } public Guid QuestionOwnerTenantId { get; set; } public Guid QuestionId { get; set; } public int WrongCount { get; set; } = 1; public DateTimeOffset LastWrongAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset? ResolvedAt { get; set; } public Guid TenantId { get; set; } } public sealed class RecentPractice : AuditableTenantEntity { public Guid? UserId { get; set; } public string? LegacyId { get; set; } public string? PracticeType { get; set; } public string? TargetLegacyId { get; set; } public string? TargetName { get; set; } public int Progress { get; set; } public string? Color { get; set; } public DateTimeOffset? LastAccessAt { get; set; } public DateTimeOffset? LastPracticeAt { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); }