using EntitlementBLL.Common; using EntitlementDAL.DTOs; using EntitlementDAL.Interfaces; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using static GB5Shared.GB5Constant.Constant; namespace EntitlementBLL.Demo; public class DemoCatalogBLL : IDemoCatalogBLL { private readonly IDemoDAL _DemoDAL; private readonly IQueryExecutor _QueryExecutor; private readonly AutoNumber _AutoNumber; private readonly IEntitlementLoginFactory _LoginFactory; public DemoCatalogBLL(IDemoDAL demoDAL, IQueryExecutor queryExecutor, AutoNumber autoNumber, IEntitlementLoginFactory loginFactory) { _DemoDAL = demoDAL; _QueryExecutor = queryExecutor; _AutoNumber = autoNumber; _LoginFactory = loginFactory; } public async Task CreateVariantAsync(DemoVariantDTO dto, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (string.IsNullOrWhiteSpace(dto.VariantCode)) throw new ArgumentException("VariantCode is required.", nameof(dto)); if (string.IsNullOrWhiteSpace(dto.VariantName)) throw new ArgumentException("VariantName is required.", nameof(dto)); if (dto.DbModelId <= 0) throw new ArgumentException("DbModelId is required.", nameof(dto)); var login = _LoginFactory.Create(-1); var auto = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.ENTITLEMENTDEMOVARIANT, login).ConfigureAwait(false); var now = DateTime.UtcNow; dto.DemoVariantId = auto.StartNumber; dto.CreatedById = login.UserId; dto.CreatedOn = now; dto.ModifiedById = login.UserId; dto.ModifiedOn = now; var tx = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { await _DemoDAL.SaveVariantAsync(dto, login, tx, ct).ConfigureAwait(false); await _QueryExecutor.CommitAsync(tx).ConfigureAwait(false); } catch { await _QueryExecutor.RollbackAsync(tx).ConfigureAwait(false); throw; } return dto; } public async Task GetVariantByIdAsync(int demoVariantId, CancellationToken ct) => await _DemoDAL.GetVariantByIdAsync(demoVariantId, _LoginFactory.Create(-1), ct).ConfigureAwait(false); public async Task> GetVariantListAsync(CancellationToken ct) => await _DemoDAL.GetVariantListAsync(_LoginFactory.Create(-1), ct).ConfigureAwait(false); public async Task CreatePoolInstanceAsync(DemoPoolInstanceDTO dto, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (dto.DemoVariantId <= 0) throw new ArgumentException("DemoVariantId is required.", nameof(dto)); if (dto.SwClientDatabaseId <= 0) throw new ArgumentException("SwClientDatabaseId is required — register the physical database via SqlWorkbench's ClientProvisioning pipeline first.", nameof(dto)); var login = _LoginFactory.Create(-1); _ = await _DemoDAL.GetVariantByIdAsync(dto.DemoVariantId, login, ct).ConfigureAwait(false) ?? throw new InvalidOperationException($"DemoVariantId {dto.DemoVariantId} not found."); var auto = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.ENTITLEMENTDEMOPOOLINSTANCE, login).ConfigureAwait(false); var now = DateTime.UtcNow; dto.DemoPoolInstanceId = auto.StartNumber; // A newly-registered pool instance always starts Available, regardless of caller input — // it's this method's own job to bring a real physical database into the pool, not to let // a caller register one pre-claimed/pre-retired. dto.PoolState = (byte)DemoPoolState.Available; dto.CreatedById = login.UserId; dto.CreatedOn = now; dto.ModifiedById = login.UserId; dto.ModifiedOn = now; var tx = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { await _DemoDAL.SavePoolInstanceAsync(dto, login, tx, ct).ConfigureAwait(false); await _QueryExecutor.CommitAsync(tx).ConfigureAwait(false); } catch { await _QueryExecutor.RollbackAsync(tx).ConfigureAwait(false); throw; } return dto; } public async Task> GetPoolInstancesByVariantAsync(int demoVariantId, CancellationToken ct) => await _DemoDAL.GetPoolInstancesByVariantAsync(demoVariantId, _LoginFactory.Create(-1), ct).ConfigureAwait(false); public async Task UpdateVariantAsync(DemoVariantDTO dto, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (dto.DemoVariantId <= 0) throw new ArgumentException("DemoVariantId is required.", nameof(dto)); if (string.IsNullOrWhiteSpace(dto.VariantName)) throw new ArgumentException("VariantName is required.", nameof(dto)); if (dto.DbModelId <= 0) throw new ArgumentException("DbModelId is required.", nameof(dto)); var login = _LoginFactory.Create(-1); _ = await _DemoDAL.GetVariantByIdAsync(dto.DemoVariantId, login, ct).ConfigureAwait(false) ?? throw new InvalidOperationException($"DemoVariantId {dto.DemoVariantId} not found."); dto.ModifiedById = login.UserId; dto.ModifiedOn = DateTime.UtcNow; var tx = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { await _DemoDAL.UpdateVariantAsync(dto, login, tx, ct).ConfigureAwait(false); await _QueryExecutor.CommitAsync(tx).ConfigureAwait(false); } catch { await _QueryExecutor.RollbackAsync(tx).ConfigureAwait(false); throw; } return dto; } public async Task UpdatePoolInstanceAsync(DemoPoolInstanceDTO dto, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (dto.DemoPoolInstanceId <= 0) throw new ArgumentException("DemoPoolInstanceId is required.", nameof(dto)); if (dto.SwClientDatabaseId <= 0) throw new ArgumentException("SwClientDatabaseId is required — register the physical database via SqlWorkbench's ClientProvisioning pipeline first.", nameof(dto)); var login = _LoginFactory.Create(-1); _ = await _DemoDAL.GetPoolInstanceByIdAsync(dto.DemoPoolInstanceId, login, ct).ConfigureAwait(false) ?? throw new InvalidOperationException($"DemoPoolInstanceId {dto.DemoPoolInstanceId} not found."); dto.ModifiedById = login.UserId; dto.ModifiedOn = DateTime.UtcNow; var tx = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { await _DemoDAL.UpdatePoolInstanceAsync(dto, login, tx, ct).ConfigureAwait(false); await _QueryExecutor.CommitAsync(tx).ConfigureAwait(false); } catch { await _QueryExecutor.RollbackAsync(tx).ConfigureAwait(false); throw; } return dto; } }