using GB5Shared.DaprCache; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.EventLogPublish; using GB5Shared.Resource.Response; using GB5Shared.Telemetry; using GB5Shared.Validation; using Microsoft.Extensions.Logging; using OKRBLL.Interfaces; using OKRDAL.DTOs; using OKRDAL.Interfaces; using System.Text.Json; using static GB5Shared.GB5Constant.Constant; namespace OKRBLL.Implementations; public class OKRCycleBLL : IOKRCycleBLL { private readonly IOKRCycleDAL _dal; private readonly IGoalDAL _goalDal; private readonly IObjectiveDAL _objectiveDal; private readonly IValidation _validation; private readonly KeyInvalidate _keyInvalidate; private readonly EventLogPublish _eventLog; private readonly ILogger _logger; public OKRCycleBLL( IOKRCycleDAL dal, IGoalDAL goalDal, IObjectiveDAL objectiveDal, IValidation validation, KeyInvalidate keyInvalidate, EventLogPublish eventLog, ILogger logger) { _dal = dal; _goalDal = goalDal; _objectiveDal = objectiveDal; _validation = validation; _keyInvalidate = keyInvalidate; _eventLog = eventLog; _logger = logger; } public async Task GetOKRCycleAsync(int okrCycleId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("get-okrcycle", new { okrCycleId }); var dto = await _dal.GetCycleAsync(okrCycleId, login, ct).ConfigureAwait(false); return JsonSerializer.Serialize(dto); } catch (Exception ex) { GB5Trace.MarkFailed("get-okrcycle-failed", ex); _logger.LogError(ex, "GetOKRCycle failed for OKRCycleId {OKRCycleId}", okrCycleId); throw; } } public async Task GetOKRCycleListAsync(int status, int page, int pageSize, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("get-okrcycle-list", new { status, page }); var list = await _dal.GetCycleListAsync(status, page, pageSize, login, ct).ConfigureAwait(false); return JsonSerializer.Serialize(list); } catch (Exception ex) { GB5Trace.MarkFailed("get-okrcycle-list-failed", ex); _logger.LogError(ex, "GetOKRCycleList failed"); throw; } } public async Task GetSelectListAsync(CriteriaDTO criteriaDTO, LoginDTO login, CancellationToken ct) { try { var list = await _dal.GetSelectListAsync(criteriaDTO, login, ct).ConfigureAwait(false); return JsonSerializer.Serialize(list); } catch (Exception ex) { GB5Trace.MarkFailed("get-okrcycle-selectlist-failed", ex); _logger.LogError(ex, "GetSelectListOKRCycle failed"); throw; } } public async Task SaveOKRCycleAsync(OKRCycleDTO dto, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("validate-okrcycle", new { dto.OKRCycleId }); await _validation.NotEmpty(dto.Code, nameof(dto.Code)).ConfigureAwait(false); await _validation.NotEmpty(dto.Name, nameof(dto.Name)).ConfigureAwait(false); if (dto.CycleEnd <= dto.CycleStart) return "CycleEnd must be after CycleStart."; bool isNew = dto.OKRCycleId == 0; GB5Trace.Step("save-okrcycle", new { dto.OKRCycleId, isNew }); int cycleId = await _dal.SaveCycleAsync(dto, login, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.SAVEOKRCYCLEEVENTTYPEID }); await _eventLog.PublishEventLogAsync( isNew ? "OKR Cycle Created" : "OKR Cycle Updated", new { dto.Code, dto.Name }, EventTypeConstant.SAVEOKRCYCLEEVENTTYPEID, cycleId, login, ct: ct).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration(cycleId, EntityConstant.OBJECTOKRCYCLE, CacheKeyLevel.CLIENT_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {cycleId}" : SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("save-okrcycle-failed", ex); _logger.LogError(ex, "SaveOKRCycle failed for Code {Code}", dto.Code); throw; } } public async Task CloseOKRCycleAsync(int okrCycleId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("validate-close-okrcycle", new { okrCycleId }); var cycle = await _dal.GetCycleAsync(okrCycleId, login, ct).ConfigureAwait(false); if (cycle is null) return "OKR cycle not found."; if (cycle.Status != 1) return "Only an Active OKR cycle can be closed."; GB5Trace.Step("close-okrcycle", new { okrCycleId }); await _dal.CloseCycleAsync(okrCycleId, login, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.CLOSEOKRCYCLEEVENTTYPEID }); await _eventLog.PublishEventLogAsync( "OKR Cycle Closed", new { OKRCycleId = okrCycleId, cycle.Code }, EventTypeConstant.CLOSEOKRCYCLEEVENTTYPEID, okrCycleId, login, ct: ct).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration(okrCycleId, EntityConstant.OBJECTOKRCYCLE, CacheKeyLevel.CLIENT_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("close-okrcycle-failed", ex); _logger.LogError(ex, "CloseOKRCycle failed for OKRCycleId {OKRCycleId}", okrCycleId); throw; } } }