using AutomationDAL.CustomCode.Target; using AutomationDAL.DTO.Target; using GB5Shared.DTO.Framework.Login; using GB5Shared.Resource.Response; using GB5Shared.Telemetry; using Microsoft.Extensions.Logging; namespace AutomationBLL.Target; public class TargetBLL : ITargetBLL { private static readonly string[] ValidEnvironments = { "Dev", "Test", "Prod" }; private readonly ITargetDAL _dal; private readonly ILogger _logger; public TargetBLL(ITargetDAL dal, ILogger logger) { _dal = dal; _logger = logger; } public async Task GetById(int targetId, LoginDTO login, CancellationToken ct) => await _dal.GetById(targetId, login, ct).ConfigureAwait(false); public async Task> GetByScript(int scriptId, LoginDTO login, CancellationToken ct) => await _dal.GetByScript(scriptId, login, ct).ConfigureAwait(false); public async Task Save(TargetDTO dto, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("validate-target", new { dto.TargetId, dto.ScriptId, dto.TargetName }); if (dto.ScriptId <= 0) throw new InvalidOperationException("ScriptId is required."); if (string.IsNullOrWhiteSpace(dto.TargetName)) throw new InvalidOperationException("TargetName is required."); if (!ValidEnvironments.Contains(dto.Environment)) throw new InvalidOperationException($"Environment must be one of: {string.Join(", ", ValidEnvironments)}"); if (dto.ConcurrencyLimit <= 0) throw new InvalidOperationException("ConcurrencyLimit must be greater than zero."); var isNew = dto.TargetId == 0; GB5Trace.Step("save-target", new { dto.TargetId, isNew }); if (isNew) { int newId = await _dal.Insert(dto, login, ct).ConfigureAwait(false); return $"{SuccessResponse.SaveSuccessMessage} {newId}"; } await _dal.Update(dto, login, ct).ConfigureAwait(false); return SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("save-target-failed", ex); _logger.LogError(ex, "Save failed for TargetName {TargetName}", dto.TargetName); throw; } } public async Task Enable(int targetId, LoginDTO login, CancellationToken ct) { try { var target = await _dal.GetById(targetId, login, ct).ConfigureAwait(false) ?? throw new InvalidOperationException($"Target {targetId} not found."); GB5Trace.Step("enable-target", new { targetId, target.Environment, ApprovedById = login.UserId }); int rows = await _dal.Enable(targetId, login.UserId, target.CreatedById, login, ct).ConfigureAwait(false); if (rows == 0) throw new InvalidOperationException( "Cannot enable: Prod targets require a second approver — the approving user must differ from the user who created the target."); return SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("enable-target-failed", ex); _logger.LogError(ex, "Enable failed for TargetId {TargetId}", targetId); throw; } } public async Task Disable(int targetId, LoginDTO login, CancellationToken ct) { await _dal.Disable(targetId, login, ct).ConfigureAwait(false); return SuccessResponse.UpdateSuccess; } }