using System.Text.Json; using CMGMBLL.Interfaces; using CMGMDAL.DTOs; using CMGMDAL.Interfaces; using GB5Shared.DaprCache; using GB5Shared.DTO.Framework.Login; using GB5Shared.EventLogPublish; using GB5Shared.Resource.Response; using GB5Shared.Telemetry; using static GB5Shared.GB5Constant.Constant; using Microsoft.Extensions.Logging; namespace CMGMBLL.Implementations; public class CompetencyAnchorBLL : ICompetencyAnchorBLL { private readonly ICompetencyAnchorDAL _dal; private readonly KeyInvalidate _keyInvalidate; private readonly EventLogPublish _eventLog; private readonly ILogger _logger; public CompetencyAnchorBLL(ICompetencyAnchorDAL dal, KeyInvalidate keyInvalidate, EventLogPublish eventLog, ILogger logger) { _dal = dal; _keyInvalidate = keyInvalidate; _eventLog = eventLog; _logger = logger; } public async Task GetBySkillAsync(int skillId, LoginDTO login, CancellationToken ct) { try { var list = await _dal.GetBySkillAsync(skillId, login, ct).ConfigureAwait(false); return JsonSerializer.Serialize(list); } catch (Exception ex) { GB5Trace.MarkFailed("get-anchor-failed", ex); _logger.LogError(ex, "GetAnchorsBySkill failed for SkillId {SkillId}", skillId); throw; } } public async Task SaveAsync(CompetencyAnchorDTO dto, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("validate-anchor", new { dto.AnchorId }); if (dto.SkillId <= 0) return "Skill is required."; if (dto.ProficiencyLevel is < 1 or > 5) return "Proficiency level must be between 1 and 5."; if (string.IsNullOrWhiteSpace(dto.AnchorText)) return "Anchor text is required."; bool isNew = dto.AnchorId == 0; GB5Trace.Step("save-anchor", new { dto.AnchorId, isNew }); int savedId = await _dal.SaveAsync(dto, isNew, login, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.SAVECOMPETENCYANCHOREVENTTYPEID }); await _eventLog.PublishEventLogAsync("Competency Anchor Saved", dto, EventTypeConstant.SAVECOMPETENCYANCHOREVENTTYPEID, savedId, login, ct: ct).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration(dto.SkillId, EntityConstant.OBJECTCOMPETENCYANCHOR, CacheKeyLevel.CLIENT_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {savedId}" : SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("save-anchor-failed", ex); _logger.LogError(ex, "SaveAnchor failed for SkillId {SkillId} Level {Level}", dto.SkillId, dto.ProficiencyLevel); throw; } } public async Task DeleteAsync(int anchorId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("delete-anchor", new { anchorId }); await _dal.DeleteAsync(anchorId, login, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.SAVECOMPETENCYANCHOREVENTTYPEID }); await _eventLog.PublishEventLogAsync("Competency Anchor Deleted", new { AnchorId = anchorId }, EventTypeConstant.SAVECOMPETENCYANCHOREVENTTYPEID, anchorId, login, ct: ct).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration(anchorId, EntityConstant.OBJECTCOMPETENCYANCHOR, CacheKeyLevel.CLIENT_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { GB5Trace.MarkFailed("delete-anchor-failed", ex); _logger.LogError(ex, "DeleteAnchor failed for AnchorId {AnchorId}", anchorId); throw; } } }