using FrameworkDAL.CustomCode.EIPConversation.EIPCapabilityAdmin; using FrameworkDAL.DTO.EIPConversation; using GB5Shared.DTO.Framework.Login; using GB5Shared.Resource.Response; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; namespace FrameworkBLL.EIPConversation.EIPAdmin.EIPCapabilityAdmin { public class EIPCapabilityAdminBLL : IEIPCapabilityAdminBLL { private static readonly Regex CapabilityCodePattern = new(@"^[A-Za-z0-9_]{1,100}$", RegexOptions.Compiled); private readonly IEIPCapabilityAdminDAL _dal; private readonly ILogger _logger; public EIPCapabilityAdminBLL( IEIPCapabilityAdminDAL dal, ILogger logger) { _dal = dal ?? throw new ArgumentNullException(nameof(dal)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task> GetCapabilityListAsync( string? search, LoginDTO login, CancellationToken ct = default) { try { _logger.LogInformation( "BLL | GetCapabilityList | Tenant={TenantId} | Search={Search}", login.ClientId, search); return await _dal.GetCapabilityListAsync(search, login, ct).ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "BLL | GetCapabilityList | Error | Tenant={TenantId}", login.ClientId); throw; } } public async Task GetCapabilityAsync( int capabilityId, LoginDTO login, CancellationToken ct = default) { try { _logger.LogInformation( "BLL | GetCapability | Tenant={TenantId} | CapabilityId={CapabilityId}", login.ClientId, capabilityId); return await _dal.GetCapabilityAsync(capabilityId, login, ct).ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "BLL | GetCapability | Error | CapabilityId={CapabilityId}", capabilityId); throw; } } public async Task SaveCapabilityAsync( EIPCapabilityAdminDTO dto, LoginDTO login, CancellationToken ct = default) { try { _logger.LogInformation( "BLL | SaveCapability | Validate | Tenant={TenantId} | CapabilityCode={CapabilityCode}", login.ClientId, dto.CapabilityCode); ValidateCapabilityCode(dto.CapabilityCode); ValidateRiskLevel(dto.RiskLevel); if (string.IsNullOrWhiteSpace(dto.CapabilityName)) throw new ArgumentException("CapabilityName is required."); // CAPABILITYCODE is globally unique (UK_MEIPCAPABILITY_CAPABILITYCODE) — not per-tenant. bool codeExists = await _dal.CapabilityCodeExistsAsync( dto.CapabilityCode, dto.CapabilityId, login, ct).ConfigureAwait(false); if (codeExists) throw new InvalidOperationException( $"CapabilityCode '{dto.CapabilityCode}' already exists."); dto.TenantId = login.ClientId; var isNew = dto.CapabilityId == 0; _logger.LogInformation( "BLL | SaveCapability | Persist | Tenant={TenantId} | CapabilityCode={CapabilityCode} | IsNew={IsNew}", login.ClientId, dto.CapabilityCode, isNew); if (isNew) { var newId = await _dal.InsertCapabilityAsync(dto, login, ct).ConfigureAwait(false); _logger.LogInformation("BLL | SaveCapability | Inserted | NewId={NewId}", newId); return $"{SuccessResponse.SaveSuccessMessage} {newId}"; } else { await _dal.UpdateCapabilityAsync(dto, login, ct).ConfigureAwait(false); _logger.LogInformation( "BLL | SaveCapability | Updated | CapabilityId={Id}", dto.CapabilityId); return SuccessResponse.UpdateSuccess; } } catch (Exception ex) { _logger.LogError(ex, "BLL | SaveCapability | Error | Tenant={TenantId} | CapabilityCode={CapabilityCode}", login.ClientId, dto.CapabilityCode); throw; } } public async Task DeleteCapabilityAsync( int capabilityId, LoginDTO login, CancellationToken ct = default) { try { _logger.LogInformation( "BLL | DeleteCapability | Tenant={TenantId} | CapabilityId={CapabilityId}", login.ClientId, capabilityId); if (capabilityId == 0) throw new ArgumentException("CapabilityId must be a positive integer."); await _dal.DeleteCapabilityAsync(capabilityId, login, ct).ConfigureAwait(false); _logger.LogInformation( "BLL | DeleteCapability | Completed | CapabilityId={CapabilityId}", capabilityId); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { _logger.LogError(ex, "BLL | DeleteCapability | Error | CapabilityId={CapabilityId}", capabilityId); throw; } } private static void ValidateCapabilityCode(string capabilityCode) { if (string.IsNullOrWhiteSpace(capabilityCode)) throw new ArgumentException("CapabilityCode is required."); if (!CapabilityCodePattern.IsMatch(capabilityCode)) throw new ArgumentException( "CapabilityCode must contain only alphanumeric characters and underscores (max 100 chars)."); } private static void ValidateRiskLevel(byte riskLevel) { if (riskLevel < 1 || riskLevel > 4) throw new ArgumentException( "RiskLevel must be one of: 1=Low, 2=Medium, 3=High, 4=Critical."); } } }