using GB5Shared.DaprCache; using GB5Shared.DTO.Framework.AutoNumber; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using GB5Shared.Validation; using System.ComponentModel.DataAnnotations; using TMSDAL.CustomCode.QuestionBank; using TMSDAL.DTO.QuestionBank; using static GB5Shared.GB5Constant.Constant; namespace TMSBLL.QuestionBank { public class QuestionBankBLL : IQuestionBankBLL { private readonly IQuestionBankDAL _QuestionBankDAL; private readonly AutoNumber _AutoNumber; private readonly IValidation _Validation; private readonly KeyInvalidate _KeyInvalidate; public QuestionBankBLL( IQuestionBankDAL questionBankDAL, AutoNumber autoNumber, IValidation validation, KeyInvalidate keyInvalidate) { _QuestionBankDAL = questionBankDAL; _AutoNumber = autoNumber; _Validation = validation; _KeyInvalidate = keyInvalidate; } // ═══════════════════════════════════════════════════════════════════════ // GET // ═══════════════════════════════════════════════════════════════════════ public async Task GetQuestionBank(int questionBankId, LoginDTO loginDTO) { try { return await _QuestionBankDAL.GetQuestionBank(questionBankId, loginDTO); } catch (Exception) { throw; } } public async Task GetQuestionBankList(LoginDTO loginDTO) { try { return await _QuestionBankDAL.GetQuestionBankList(loginDTO); } catch (Exception) { throw; } } public async Task GetSelectListQuestionBank(CriteriaDTO criteriaDTO, LoginDTO loginDTO) => await _QuestionBankDAL.GetSelectListQuestionBank(criteriaDTO, loginDTO); public async Task GetQuestionsForSection(int assessmentPaperId, int paperSectionId, LoginDTO loginDTO) { try { return await _QuestionBankDAL.GetQuestionsForSection(assessmentPaperId, paperSectionId, loginDTO); } catch (Exception) { throw; } } // ═══════════════════════════════════════════════════════════════════════ // SAVE / UPDATE // ═══════════════════════════════════════════════════════════════════════ public async Task SaveQuestionBank(QuestionBankDTO dto, LoginDTO loginDTO) { if (dto == null) throw new ArgumentNullException(nameof(dto)); AutoNumberDTO? autoNumberDTO = null; try { // ── Validations ────────────────────────────────────────────── await _Validation.NotEmpty(dto.QuestionTitle, nameof(dto.QuestionTitle)); await _Validation.NotEmpty(dto.QuestionText, nameof(dto.QuestionText)); await _Validation.NotEmpty(dto.CorrectAnswer, nameof(dto.CorrectAnswer)); dto.TenantId = dto.IsShared == 1 ? -1 : loginDTO.ClientId; dto.ModifiedById = loginDTO.UserId; dto.ModifiedOn = DateTime.UtcNow; string message; if (dto.QuestionBankId == 0) { // ── INSERT ─────────────────────────────────────────────── autoNumberDTO = await _AutoNumber.GetAutoNumber(1, "QUESTIONBANK", loginDTO); dto.QuestionBankId = autoNumberDTO.StartNumber; dto.CreatedById = loginDTO.UserId; dto.CreatedOn = DateTime.UtcNow; await _QuestionBankDAL.SaveQuestionBank(dto, loginDTO); message = string.Format(SuccessResponse.SaveSuccessWithName, dto.QuestionTitle); } else { // ── UPDATE ─────────────────────────────────────────────── await _QuestionBankDAL.UpdateQuestionBank(dto, loginDTO); message = string.Format(SuccessResponse.UpdateSuccessWithName, dto.QuestionTitle); } // ── Cache Invalidation ─────────────────────────────────────── var cacheKey = new CacheKeyGeneration().KeyGeneration( dto.QuestionBankId, EntityConstant.OBJECTQUESTIONBANK, CacheKeyLevel.CLIENT_LEVEL, loginDTO); await _KeyInvalidate.AllInvalidateCache(cacheKey); return message; } catch (ValidationException vex) { throw new Exception(vex.Message); } catch (Exception) { // ── Rollback AutoNumber on failure ─────────────────────────── if (autoNumberDTO != null && dto.QuestionBankId > 0) await _AutoNumber.RollbackAutoNumber("QUESTIONBANK", dto.QuestionBankId, loginDTO); throw; } } // ═══════════════════════════════════════════════════════════════════════ // DELETE // ═══════════════════════════════════════════════════════════════════════ public async Task DeleteQuestionBank(int questionBankId, LoginDTO loginDTO) { try { var result = await _QuestionBankDAL.DeleteQuestionBank(questionBankId, loginDTO); // ── Cache Invalidation ─────────────────────────────────────── var cacheKey = new CacheKeyGeneration().KeyGeneration( questionBankId, EntityConstant.OBJECTQUESTIONBANK, CacheKeyLevel.CLIENT_LEVEL, loginDTO); await _KeyInvalidate.AllInvalidateCache(cacheKey); return result; } catch (Exception) { throw; } } // ═══════════════════════════════════════════════════════════════════════ // USAGE COUNT // ═══════════════════════════════════════════════════════════════════════ public async Task IncrementUsageCount(int questionBankId, LoginDTO loginDTO) { try { return await _QuestionBankDAL.IncrementUsageCount(questionBankId, loginDTO); } catch (Exception) { throw; } } } }