using EntitlementDAL.DTOs; namespace EntitlementBLL.Demo; /// Thread 3 (Demo/DemoDB, tracker §49) — registration, checkout/extension/expiry /// lifecycle for both Pooled and Dedicated demo sessions. public interface IDemoSessionBLL { /// Decision 9 — the shared, lightweight first step for EVERY demo request (Pooled /// or Dedicated alike): creates a real central MCLIENT/MUSER account (reusing /// IClientProvisioningBLL.CreateClientAsync — identity only, no DB provisioning, so this is /// fast enough for a public landing-page form) and captures the prospect's industry/product/ /// plan/feature preference. The returned ClientId is what CheckOutPooledSessionRequest/ /// StartDedicatedSessionRequest both require. Task RegisterProspectAsync(RegisterDemoProspectRequest req, CancellationToken ct); Task CheckOutPooledSessionAsync(CheckOutPooledSessionRequest req, CancellationToken ct); /// Reuses IClientOnboardingOrchestratorBLL.StartOnboardingAsync, now passing /// ExistingClientId/ExistingUserId (from the prior RegisterProspectAsync call) so it /// provisions a real physical DB for the SAME central account instead of creating a second, /// duplicate identity — a Dedicated demo gets a real login for a multi-day evaluation. Task StartDedicatedSessionAsync(StartDedicatedSessionRequest req, CancellationToken ct); Task GetByIdAsync(int demoSessionId, CancellationToken ct); Task> GetListByOwnerAsync(int ownerUserId, CancellationToken ct); Task RequestExtensionAsync(int demoSessionId, string? comment, CancellationToken ct); /// Only the session's own OwnerUserId (the sales/CS rep who owns the engagement) may /// approve — per the user's own confirmed choice, tracker §49 Decision 5. Task ApproveExtensionAsync(int demoSessionId, int approvedById, DateTime newExpiresOn, CancellationToken ct); Task RejectExtensionAsync(int demoSessionId, int rejectedById, CancellationToken ct); /// Background worker entry point (mirrors RolloutCampaignWorkerJob's own shape) — /// issues warnings for sessions approaching expiry, expires sessions past expiry, and (Pooled /// only) resets the underlying pool instance for reuse. Returns the number of sessions /// touched (warned + expired) this pass. Task ProcessExpiringAndExpiredSessionsAsync(CancellationToken ct); } /// Decision 9's simple, landing-page-driven registration form — deliberately no /// ClientCode/AdminUserCode (server-derived, same discipline as /// ClientOnboardingOrchestratorBLL.StartSelfServiceTrialAsync, so an anonymous caller can't /// spoof/collide with another client's code). public class RegisterDemoProspectRequest { public string CompanyName { get; set; } = string.Empty; public string ContactName { get; set; } = string.Empty; public string Email { get; set; } = string.Empty; public string Mobile { get; set; } = string.Empty; /// Soft reference, no hard FK — TPARTNERPRODUCT.PartnerProductId; null = GB5 default. public int? PreferredPartnerProductId { get; set; } public int? PreferredPlanId { get; set; } public string PreferredIndustryCode { get; set; } = string.Empty; public string PreferredGeographyCode { get; set; } = string.Empty; public int? PreferredFeatureId { get; set; } // Legal/Contract Agreement Consent jurisdiction resolution (tracker §51.12) — deliberately // distinct from PreferredGeographyCode above: that's content-selection taxonomy for picking a // demo variant (e.g. "Africa"/"FarEast"), not a legal jurisdiction code. Optional. public string? JurisdictionCode { get; set; } // Legal/Contract Agreement Consent (tracker §50/§51) — mirrors // SelfProvisionTrialRequestDTO.AcceptedAgreementVersionIds exactly: the exact // AgreementVersionIds the caller was shown (via Legal/GetApplicableAgreements) and ticked // to accept. Optional/empty is tolerated (no acceptance recorded, nothing blocked). public int[] AcceptedAgreementVersionIds { get; set; } = Array.Empty(); } /// The one place the first admin's plaintext temporary password is visible — same /// convention as CreateClientResultDTO/SelfProvisionTrialResultDTO. public class RegisterDemoProspectResultDTO { public int ClientId { get; set; } public int UserId { get; set; } public string TemporaryPassword { get; set; } = string.Empty; } public class CheckOutPooledSessionRequest { /// From a prior RegisterProspectAsync call — the central account this session /// belongs to (Decision 9: required for Pooled mode too, not just Dedicated). public int ClientId { get; set; } /// From the same prior RegisterProspectAsync call as ClientId — needed to seed the /// real per-prospect MUSER inside the pool instance's own database with the same Name/Email /// already captured centrally, rather than asking for it a second time. public int UserId { get; set; } public int DemoVariantId { get; set; } public int OwnerUserId { get; set; } public int DurationHours { get; set; } = 24; /// Optional — the role the prospect wants to see (e.g. "TMS_TRAINER"), matched /// against MDEMOVARIANT.AvailableDemoRoleCodes. Stored on the session for reporting; the /// actual per-prospect MUSER-inside-the-pool-DB creation this drives is designed (Decision /// 8/9) but not yet built — see tracker §49's own drift notes. public string? DemoRoleCode { get; set; } /// Direction B (a CRM sales exec pushing a demo to an existing lead) — set directly; /// left null for Direction A (self-service). public int? LeadId { get; set; } } public class StartDedicatedSessionRequest { /// From a prior RegisterProspectAsync call — reused, never a second identity for /// the same prospect (Decision 9). Threaded onto OnboardRequest.ExistingClientId/UserId. public int ClientId { get; set; } public int UserId { get; set; } public OnboardClientRequestDTO OnboardRequest { get; set; } = new(); public int OwnerUserId { get; set; } public int DurationDays { get; set; } = 14; public int? LeadId { get; set; } }