using System.Text.Json; using Tiku.Application.Catalog; using Tiku.Domain.Content; namespace Tiku.Application.Assets; public sealed record VideoPlaybackActor(Guid TenantId, Guid UserId); public sealed record VideoSearchQuery( string? Keyword = null, Guid? SubjectId = null, int? Limit = null); public sealed record QuestionVideoQuery( Guid? QuestionId = null, IReadOnlyCollection? QuestionIds = null, int? Limit = null); public sealed record VideoPlayCommand(Guid VideoId, Guid? QuestionId = null); public sealed record VideoProgressCommand( Guid VideoId, Guid? QuestionId, int PositionSeconds, int? DurationSeconds, int? WatchedSeconds, bool? IsCompleted, JsonElement Metadata); public sealed record VideoPlaybackItem( Guid VideoId, Guid? QuestionId, string Title, string? Description, string? PlayUrl, string? ThumbnailUrl, int? DurationSeconds, VideoProgressItem? Progress, JsonElement Metadata); public sealed record VideoProgressItem( Guid Id, Guid VideoId, Guid? QuestionId, int PositionSeconds, int? DurationSeconds, int WatchedSeconds, bool IsCompleted, DateTimeOffset? CompletedAt, DateTimeOffset LastPlayedAt, int PlayCount, JsonElement Metadata); public interface IVideoPlaybackService { Task> SearchAsync( VideoPlaybackActor actor, VideoSearchQuery query, CancellationToken cancellationToken = default); Task PlayAsync( VideoPlaybackActor actor, VideoPlayCommand command, CancellationToken cancellationToken = default); Task ReportProgressAsync( VideoPlaybackActor actor, VideoProgressCommand command, CancellationToken cancellationToken = default); Task> GetQuestionVideosAsync( VideoPlaybackActor actor, QuestionVideoQuery query, CancellationToken cancellationToken = default); } public sealed class VideoPlaybackException(string message, string code) : Exception(message) { public string Code { get; } = code; }