using System.Text.Json; namespace Tiku.Application.Growth; public sealed record ReferralActor(Guid TenantId, Guid? UserId = null); public sealed record ReferralAdminActor(Guid TenantId, Guid UserId); public sealed record ReferralInviteCommand(string? Channel = null, string? LandingPath = null); public sealed record ResolveReferralCommand(string? Code); public sealed record TrackReferralEventCommand( string RefCode, string? EventType, string? Source, Guid? TargetUserId, JsonElement? Metadata); public sealed record BindReferralCommand( string RefCode, string? Source, JsonElement? Metadata); public sealed record ReferralQrcodeCommand( string? Page, string? Scene, string? Provider, string? QrcodeUrl, JsonElement? Metadata); public sealed record ReferralQrcodeGenerateRequest( Guid TenantId, Guid UserId, string RefCode, string Provider, string Page, string Scene); public sealed record ReferralQrcodeGenerateResult( string QrcodeUrl, string Provider, JsonElement Metadata); public sealed record ReferralStatsQuery(Guid? ReferrerUserId = null, int? Limit = null); public sealed record ReferralConversionQuery( Guid? ReferrerUserId = null, DateOnly? StartDate = null, DateOnly? EndDate = null, int? Days = null, int? Limit = null); public sealed record ManualBindReferralCommand( Guid StudentUserId, Guid ReferrerUserId, string? Source, bool Force, JsonElement? Metadata); public sealed record ReferralTeamQuery(Guid? LeaderUserId = null); public sealed record UpsertReferralTeamCommand( Guid MemberUserId, Guid? LeaderUserId, string? RelationType, string? Status, JsonElement? Metadata); public sealed record ReferralInviteItem(string InviteCode); public sealed record ReferralResolutionItem( bool Valid, Guid? InviterId, string? InviteCode, string? Role, string? Name); public sealed record ReferralTrackItem( Guid Id, string EventType, string? RefCode, Guid? ReferrerUserId, Guid? TargetUserId, string? Source, DateTimeOffset CreatedAt); public sealed record ReferralLeadItem( Guid Id, Guid StudentUserId, Guid? ReferrerUserId, string? RefCode, string Status, DateTimeOffset BoundAt, bool Changed); public sealed record ReferralQrcodeItem( Guid Id, string RefCode, string Scene, string Page, string Provider, string? QrcodeUrl, string Status, JsonElement Metadata); public sealed record ReferralTrackResult(ReferralTrackItem Item, ReferralLeadItem? Lead, CrmQueuePreviewItem? CrmQueue); public sealed record ReferralBindResult(ReferralLeadItem Lead, CrmQueuePreviewItem? CrmQueue); public sealed record CrmQueuePreviewItem(Guid Id, string Status, string? Source); public sealed record ReferralStatsItem( Guid ReferrerUserId, string? Name, string Role, string? InviteCode, int LeadCount, int PaidLeadCount, int PaidAmountCents, int TrackCount, decimal ConversionRate); public sealed record ReferralList(IReadOnlyCollection Items); public sealed record ReferralConversionReport( DateOnly StartDate, DateOnly EndDate, int LeadCount, int PaidLeadCount, int PaidAmountCents, decimal ConversionRate, IReadOnlyCollection TopReferrers, IReadOnlyCollection RecentUnconvertedLeads); public sealed record ReferralTeamItem( Guid Id, Guid MemberUserId, Guid? LeaderUserId, string RelationType, string Status, JsonElement Metadata); public interface IStudentReferralService { Task GetOrCreateInviteCodeAsync( ReferralActor actor, ReferralInviteCommand command, CancellationToken cancellationToken = default); Task ResolveAsync( ReferralActor actor, ResolveReferralCommand command, CancellationToken cancellationToken = default); Task TrackEventAsync( ReferralActor actor, TrackReferralEventCommand command, string? ipAddress, string? userAgent, CancellationToken cancellationToken = default); Task BindAsync( ReferralActor actor, BindReferralCommand command, CancellationToken cancellationToken = default); Task GetOrCreateQrcodeAsync( ReferralActor actor, ReferralQrcodeCommand command, CancellationToken cancellationToken = default); } public interface IReferralAnalyticsService { Task GetStatsAsync( ReferralAdminActor actor, ReferralStatsQuery query, CancellationToken cancellationToken = default); Task> GetSalesStatsAsync( ReferralAdminActor actor, ReferralStatsQuery query, CancellationToken cancellationToken = default); Task GetConversionReportAsync( ReferralAdminActor actor, ReferralConversionQuery query, CancellationToken cancellationToken = default); Task> GetClientsAsync( ReferralAdminActor actor, ReferralStatsQuery query, CancellationToken cancellationToken = default); } public interface IReferralAdministrationService { Task ManualBindAsync( ReferralAdminActor actor, ManualBindReferralCommand command, CancellationToken cancellationToken = default); Task> GetTeamAsync( ReferralAdminActor actor, ReferralTeamQuery query, CancellationToken cancellationToken = default); Task UpsertTeamAsync( ReferralAdminActor actor, UpsertReferralTeamCommand command, CancellationToken cancellationToken = default); } public interface IReferralQrcodeGenerator { Task GenerateAsync( ReferralQrcodeGenerateRequest request, CancellationToken cancellationToken = default); } public sealed class ReferralException(string message, string code) : Exception(message) { public string Code { get; } = code; }