using AnalyticsDAL.CustomCode.KPI; using AnalyticsDAL.DTO.KPI; using GB5Shared.DaprCache; using GB5Shared.DTO.Framework.Login; using GB5Shared.Resource.Response; using GB5Shared.Telemetry; using Microsoft.Extensions.Logging; using static GB5Shared.GB5Constant.Constant; namespace AnalyticsBLL.KPI { public class KPIBLL : IKPIBLL { private readonly IKPIDAL _dal; private readonly KeyInvalidate _keyInvalidate; private readonly ILogger _logger; public KPIBLL( IKPIDAL dal, KeyInvalidate keyInvalidate, ILogger logger) { _dal = dal; _keyInvalidate = keyInvalidate; _logger = logger; } public async Task GetKPI(int kpiId, LoginDTO login, CancellationToken ct) => await _dal.GetKPI(kpiId, login, ct).ConfigureAwait(false); public async Task GetSelectListKPI(LoginDTO login, CancellationToken ct) => await _dal.GetSelectListKPI(login, ct).ConfigureAwait(false); public async Task GetKPIList(byte? measureType, int firstNumber, int maxResult, LoginDTO login, CancellationToken ct) => await _dal.GetKPIList(measureType, firstNumber, maxResult, login, ct).ConfigureAwait(false); public async Task SaveKPI(KPIDTO dto, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("validate-kpi", new { dto.KPIId }); if (string.IsNullOrWhiteSpace(dto.KPIName)) throw new ArgumentException("KPIName is required."); if (dto.KPIName.Length > 200) throw new ArgumentException("KPIName must not exceed 200 characters."); if (dto.KPISTATUSArray != null) { foreach (var row in dto.KPISTATUSArray) { if (row.KPISTATUSValueFrom >= row.KPISTATUSValueTo) throw new ArgumentException( $"Status row {row.KPISTATUSSLNo}: ValueFrom must be less than ValueTo."); } } if (await _dal.IsDuplicateName(dto.KPIName, dto.KPIId, login, ct).ConfigureAwait(false)) throw new InvalidOperationException($"KPI name '{dto.KPIName}' already exists."); var isNew = dto.KPIId == 0; GB5Trace.Step("save-kpi", new { dto.KPIId, isNew }); int savedId; if (isNew) savedId = await _dal.SaveKPI(dto, login, ct).ConfigureAwait(false); else { savedId = dto.KPIId; await _dal.UpdateKPI(dto, login, ct).ConfigureAwait(false); } var cacheKey = new CacheKeyGeneration().KeyGeneration( savedId, EntityConstant.OBJECTANALYSIS, CacheKeyLevel.CLIENT_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {savedId}" : SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("save-kpi-failed", ex); _logger.LogError(ex, "SaveKPI failed for KPIId {KPIId}", dto.KPIId); throw; } } public async Task DeleteKPI(int kpiId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("delete-kpi", new { kpiId }); await _dal.DeleteKPI(kpiId, login, ct).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration( kpiId, EntityConstant.OBJECTANALYSIS, CacheKeyLevel.CLIENT_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { GB5Trace.MarkFailed("delete-kpi-failed", ex); _logger.LogError(ex, "DeleteKPI failed for KPIId {KPIId}", kpiId); throw; } } } }