using System.Text.Json; namespace Tiku.Application.Profile; public sealed record ProfileActor(Guid TenantId, Guid UserId); public sealed record ProfileQuery(int? RecentLimit = null, int? Limit = null); public sealed record UpdateProfileCommand( string? Name, string? AvatarPreset, Guid? RegionId, Guid? SelectedSchoolId, Guid? SelectedMajorId, JsonElement? Stats, JsonElement? Progress, JsonElement? ModuleSelections, JsonElement? RecentActivities); public sealed record StudentProfileItem( Guid ProfileId, Guid UserId, string? Username, string? Phone, string? Email, string? Name, string AvatarPreset, string AvatarDisplayUrl, string PrimaryRole, int Score, Guid? RegionId, string? RegionName, Guid? SelectedSchoolId, string? SelectedSchoolName, Guid? SelectedMajorId, string? SelectedMajorName, int QuestionsAnsweredToday, int MasteredWordsCount, DateOnly? LastCheckInDate, JsonElement Stats, JsonElement Progress, JsonElement ModuleSelections, JsonElement RecentActivities, IReadOnlyCollection RecentPractices, StudentMembershipItem Membership); public sealed record RecentPracticeItem( Guid Id, string? PracticeType, string? TargetName, int Progress, DateTimeOffset? LastAccessAt, DateTimeOffset? LastPracticeAt); public sealed record StudentMembershipItem(bool IsSvip, DateTimeOffset? ExpiresAt); public sealed record ExamCountdownItem( Guid Id, string? LegacyId, Guid? RegionId, Guid? SchoolId, string ExamName, DateTimeOffset? ExamAt, string? ExamType, string? Description, JsonElement Metadata, int Order, bool IsActive, int? DaysLeft); public sealed record ExamCountdownList( IReadOnlyCollection Items, Guid? RegionId, Guid? SchoolId); public sealed record ProfileNotificationQuery(string? Status = null, int? Limit = null); public sealed record ProfileNotificationItem( Guid Id, string NotificationType, string Status, string Severity, string Title, string Message, string? ActionLabel, string? ActionPath, string? SourceType, Guid? SourceId, JsonElement Metadata, DateTimeOffset? ReadAt, DateTimeOffset CreatedAt); public sealed record ProfileNotificationList( IReadOnlyCollection Items, IReadOnlyDictionary Summary); public sealed record UpdateNotificationStatusCommand( IReadOnlyCollection NotificationIds, string? Status); public sealed record BadgeQuery(bool IncludeLocked = false, string? Category = null, int? Limit = null); public sealed record BadgeItem( Guid Id, string Name, string? Description, string? Category, string? IconUrl, int? Level, string? UnlockType, JsonElement ConditionExtra, bool IsUnlocked, DateTimeOffset? GrantedAt, string? Note, int Order); public sealed record BadgeList(IReadOnlyCollection Items, int Total, int Unlocked, bool IncludeLocked); public sealed record FeedbackQuery(string? Status = null, string? Type = null, int? Limit = null); public sealed record FeedbackItem( Guid Id, Guid? QuestionId, string? Type, string? Title, string? Category, string? Description, string Status, string Priority, string? Contact, JsonElement Attachments, JsonElement Metadata, DateTimeOffset CreatedAt, DateTimeOffset UpdatedAt); public sealed record SubmitFeedbackCommand( Guid? QuestionId, string? Type, string? Category, string? Title, string Description, string? Priority, string? Contact, JsonElement Attachments, JsonElement Metadata); public interface IProfileService { Task GetMeAsync(ProfileActor actor, ProfileQuery query, CancellationToken cancellationToken = default); Task UpdateMeAsync(ProfileActor actor, UpdateProfileCommand command, CancellationToken cancellationToken = default); Task GetExamCountdownsAsync(ProfileActor actor, ProfileQuery query, CancellationToken cancellationToken = default); Task GetNotificationsAsync(ProfileActor actor, ProfileNotificationQuery query, CancellationToken cancellationToken = default); Task UpdateNotificationStatusAsync(ProfileActor actor, UpdateNotificationStatusCommand command, CancellationToken cancellationToken = default); Task GetBadgesAsync(ProfileActor actor, BadgeQuery query, CancellationToken cancellationToken = default); Task> GetFeedbacksAsync(ProfileActor actor, FeedbackQuery query, CancellationToken cancellationToken = default); Task SubmitFeedbackAsync(ProfileActor actor, SubmitFeedbackCommand command, CancellationToken cancellationToken = default); }