using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using FrameworkDAL.CustomCode.SessionStore;
using FrameworkDAL.DTO.SessionStore;
using GB5Shared.DTO.Framework.Login;
using Microsoft.Extensions.Logging;
namespace FrameworkBLL.SessionStore
{
///
/// Session-management service for MSESSIONSTORE in the GB5 system database.
///
/// Mirrors the role of BaseEntityAppService for the session lifecycle:
/// Insert → called at login (upsert to handle re-login safely)
/// Update → called on activity heartbeat
/// Delete → called on logout or force-logout
/// Queries → consumed by the auto-logout background job
///
/// All writes target the GB5 system DB — never the tenant DB —
/// regardless of which client connection is active at call time.
///
public class SessionStoreBLL : ISessionStoreBLL
{
private readonly ISessionStoreDAL _dal;
private readonly ILogger _logger;
public SessionStoreBLL(ISessionStoreDAL dal, ILogger logger)
{
_dal = dal;
_logger = logger;
}
///
public async Task InsertSessionAsync(SessionStoreDTO dto, LoginDTO login, CancellationToken ct = default)
{
if (dto is null) throw new ArgumentNullException(nameof(dto));
// Ensure MachineIp is never null (NVARCHAR column, nullable in DB but cleaner to default)
if (string.IsNullOrEmpty(dto.MachineIp))
dto.MachineIp = string.Empty;
await _dal.UpsertSessionAsync(dto, ct).ConfigureAwait(false);
_logger.LogInformation(
"Session inserted | ServerconfigId={ServerconfigId} LoginEventLogId={LoginEventLogId} UserId={UserId}",
dto.ServerconfigId, dto.LoginEventLogId, dto.UserId);
}
///
public async Task UpdateSessionAsync(
int serverConfigId, int loginEventLogId, DateTime lastUsedTime,
LoginDTO login, CancellationToken ct = default)
{
await _dal.UpdateSessionAsync(serverConfigId, loginEventLogId, lastUsedTime, ct).ConfigureAwait(false);
}
///
public async Task DeleteSessionAsync(
int serverConfigId, int loginEventLogId,
LoginDTO login, CancellationToken ct = default)
{
if (loginEventLogId <= 0)
{
_logger.LogWarning("DeleteSession skipped — LoginEventLogId={LoginEventLogId} is invalid.", loginEventLogId);
return;
}
await _dal.DeleteSessionAsync(serverConfigId, loginEventLogId, ct).ConfigureAwait(false);
_logger.LogInformation(
"Session deleted | ServerconfigId={ServerconfigId} LoginEventLogId={LoginEventLogId}",
serverConfigId, loginEventLogId);
}
///
public async Task LogOutIfPresentAsync(
int serverConfigId, int loginEventLogId,
LoginDTO login, CancellationToken ct = default)
{
if (loginEventLogId <= 0)
{
_logger.LogWarning("LogOutIfPresent skipped — LoginEventLogId={LoginEventLogId} is invalid.", loginEventLogId);
return false;
}
int count = await _dal.GetSessionCountAsync(serverConfigId, loginEventLogId, ct).ConfigureAwait(false);
if (count == 0)
{
_logger.LogInformation(
"LogOutIfPresent — no active session | ServerconfigId={ServerconfigId} LoginEventLogId={LoginEventLogId}.",
serverConfigId, loginEventLogId);
return false;
}
await _dal.DeleteSessionAsync(serverConfigId, loginEventLogId, ct).ConfigureAwait(false);
_logger.LogInformation(
"LogOutIfPresent — session removed | ServerconfigId={ServerconfigId} LoginEventLogId={LoginEventLogId}.",
serverConfigId, loginEventLogId);
return true;
}
///
public async Task> GetUnusedSessionsAsync(
int serverConfigId, int expiryMinutes,
LoginDTO login, CancellationToken ct = default)
{
return await _dal.GetUnusedSessionsAsync(serverConfigId, expiryMinutes, ct).ConfigureAwait(false);
}
///
public async Task DeleteOldSessionsAsync(DateTime todayDate, LoginDTO login, CancellationToken ct = default)
{
await _dal.DeleteOldSessionsAsync(todayDate, ct).ConfigureAwait(false);
}
}
}