using GB5Shared.DaprCache; 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 CheckInBLL : ICheckInBLL { private readonly ICheckInDAL _dal; private readonly IValidation _validation; private readonly KeyInvalidate _keyInvalidate; private readonly EventLogPublish _eventLog; private readonly ILogger _logger; public CheckInBLL( ICheckInDAL dal, IValidation validation, KeyInvalidate keyInvalidate, EventLogPublish eventLog, ILogger logger) { _dal = dal; _validation = validation; _keyInvalidate = keyInvalidate; _eventLog = eventLog; _logger = logger; } public async Task GetCheckInAsync(int checkInId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("get-checkin", new { checkInId }); var dto = await _dal.GetCheckInAsync(checkInId, login, ct).ConfigureAwait(false); return JsonSerializer.Serialize(dto); } catch (Exception ex) { GB5Trace.MarkFailed("get-checkin-failed", ex); _logger.LogError(ex, "GetCheckIn failed for CheckInId {CheckInId}", checkInId); throw; } } public async Task GetCheckInListAsync(int goalId, int employeeId, int page, int pageSize, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("get-checkin-list", new { goalId, employeeId }); var list = await _dal.GetCheckInListAsync(goalId, employeeId, page, pageSize, login, ct).ConfigureAwait(false); return JsonSerializer.Serialize(list); } catch (Exception ex) { GB5Trace.MarkFailed("get-checkin-list-failed", ex); _logger.LogError(ex, "GetCheckInList failed for GoalId {GoalId}", goalId); throw; } } public async Task GetMyCheckInsAsync(int okrCycleId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("get-my-checkins", new { okrCycleId, login.UserId }); // ESS — EmployeeId from login.UserId, never from request var list = await _dal.GetCheckInListAsync(0, login.UserId, 1, 100, login, ct).ConfigureAwait(false); return JsonSerializer.Serialize(list); } catch (Exception ex) { GB5Trace.MarkFailed("get-my-checkins-failed", ex); _logger.LogError(ex, "GetMyCheckIns failed for UserId {UserId}", login.UserId); throw; } } public async Task SaveCheckInAsync(CheckInDTO dto, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("validate-checkin", new { dto.CheckInId }); bool isNew = dto.CheckInId == 0; GB5Trace.Step("save-checkin", new { dto.CheckInId, isNew }); int checkInId = await _dal.SaveCheckInAsync(dto, login, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.SAVEOKRCHECKINEVNTTYPEID }); await _eventLog.PublishEventLogAsync( "Check-In Saved", new { dto.GoalId, dto.EmployeeId }, EventTypeConstant.SAVEOKRCHECKINEVNTTYPEID, checkInId, login, ct: ct).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration(checkInId, EntityConstant.OBJECTCHECKIN, CacheKeyLevel.USER_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return $"{SuccessResponse.SaveSuccessMessage} {checkInId}"; } catch (Exception ex) { GB5Trace.MarkFailed("save-checkin-failed", ex); _logger.LogError(ex, "SaveCheckIn failed for GoalId {GoalId}", dto.GoalId); throw; } } public async Task SubmitCheckInAsync(int checkInId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("submit-checkin", new { checkInId }); var existing = await _dal.GetCheckInAsync(checkInId, login, ct).ConfigureAwait(false); if (existing is null) return "Check-in not found."; if (existing.Status != 0) return "Only a Draft check-in can be submitted."; await _dal.SubmitCheckInAsync(checkInId, login, ct).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration(checkInId, EntityConstant.OBJECTCHECKIN, CacheKeyLevel.USER_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("submit-checkin-failed", ex); _logger.LogError(ex, "SubmitCheckIn failed for CheckInId {CheckInId}", checkInId); throw; } } public async Task ReviewCheckInAsync(int checkInId, decimal managerProgress, string managerNotes, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("review-checkin", new { checkInId, managerProgress }); await _validation.NotEmpty(managerNotes, nameof(managerNotes)).ConfigureAwait(false); var existing = await _dal.GetCheckInAsync(checkInId, login, ct).ConfigureAwait(false); if (existing is null) return "Check-in not found."; if (existing.Status != 1) return "Only a Submitted check-in can be reviewed."; await _dal.ReviewCheckInAsync(checkInId, managerProgress, managerNotes, login, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.REVIEWOKRCHECKINEVNTTYPEID }); await _eventLog.PublishEventLogAsync( "Check-In Reviewed", new { CheckInId = checkInId, managerProgress }, EventTypeConstant.REVIEWOKRCHECKINEVNTTYPEID, checkInId, login, ct: ct).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration(checkInId, EntityConstant.OBJECTCHECKIN, CacheKeyLevel.USER_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return SuccessResponse.UpdateSuccess; } catch (Exception ex) { GB5Trace.MarkFailed("review-checkin-failed", ex); _logger.LogError(ex, "ReviewCheckIn failed for CheckInId {CheckInId}", checkInId); throw; } } }