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 SkillManagementDAL.CustomCode.SkillMatrixConfig; using SkillManagementDAL.DTO.SkillMatrixConfig; using System.Text.Json; namespace SkillManagementBLL.SkillMatrixConfig { public class SkillMatrixConfigBLL : ISkillMatrixConfigBLL { private readonly ISkillMatrixConfigDAL _dal; private readonly AutoNumber _autoNumber; private readonly IValidation _validation; public SkillMatrixConfigBLL(ISkillMatrixConfigDAL dal, AutoNumber autoNumber, IValidation validation) { _dal = dal; _autoNumber = autoNumber; _validation = validation; } public async Task GetList(LoginDTO login, CancellationToken ct) => await _dal.GetList(login, ct); public async Task GetById(int configId, LoginDTO login, CancellationToken ct) { var result = await _dal.GetById(configId, login, ct); return Newtonsoft.Json.JsonConvert.SerializeObject(result); } public async Task GetSelectList(CriteriaDTO criteriaDTO, LoginDTO login, CancellationToken ct) => await _dal.GetSelectList(criteriaDTO, login, ct); public async Task GetSkillMatrixConfigList(int firstNumber, int maxResult, CriteriaDTO criteriaDTO, LoginDTO login, CancellationToken ct) { if (firstNumber == -1 && maxResult != -1) throw new ArgumentException("MaxResult must also be -1 when FirstNumber is -1."); if (firstNumber != -1 && maxResult == -1) throw new ArgumentException("FirstNumber must also be -1 when MaxResult is -1."); if (firstNumber != -1 && firstNumber < 1) throw new ArgumentException($"FirstNumber must be >= 1 or -1. Got: {firstNumber}"); if (maxResult != -1 && maxResult < 1) throw new ArgumentException($"MaxResult must be >= 1 or -1. Got: {maxResult}"); bool isAllData = firstNumber == -1 && maxResult == -1; List data = isAllData ? await _dal.GetAllList(login, ct) : await _dal.GetPagedList(firstNumber, maxResult, login, ct); return JsonSerializer.Serialize(data); } public async Task Save(SkillMatrixConfigDTO dto, LoginDTO login, CancellationToken ct) { // ── BASIC VALIDATION ───────────────────────────── await _validation.NotEmpty(dto.MatrixCode, nameof(dto.MatrixCode)); await _validation.NotEmpty(dto.MatrixTitle, nameof(dto.MatrixTitle)); if (dto.IncludeSkillIds == null || dto.IncludeSkillIds.Count == 0) throw new ArgumentException("IncludeSkillIds must contain at least one skill."); if (dto.IncludeSkillIds.GroupBy(x => x).Any(g => g.Count() > 1)) throw new ArgumentException("Duplicate SkillIds are not allowed."); // ── SERIALIZE JSON FIELDS ──────────────────────── dto.TargetRoleIdsJson = dto.TargetRoleIds != null ? JsonSerializer.Serialize(dto.TargetRoleIds) : null; dto.ModelIdsJson = dto.ModelIds?.Count > 0 ? JsonSerializer.Serialize(dto.ModelIds) : null; dto.IncludeSkillIdsJson = JsonSerializer.Serialize(dto.IncludeSkillIds); // ── COMMON FIELDS ──────────────────────────────── var now = DateTime.UtcNow; dto.TenantId = login.ClientId; dto.ModifiedById = login.UserId; dto.ModifiedOn = now; bool isNew = dto.ConfigId == 0; AutoNumberDTO? an = null; try { if (isNew) { // ── AUTONUMBER ────────────────────────── an = await _autoNumber.GetNumberAsync(1, "MSKILLMATRIX", login); if (an == null) throw new Exception("AutoNumber failed."); dto.ConfigId = an.StartNumber; dto.CreatedById = login.UserId; dto.CreatedOn = now; await _dal.Insert(dto, login, ct); return string.Format(SuccessResponse.SaveSuccessWithCodeAndName, dto.MatrixCode, dto.MatrixTitle); } else { await _dal.Update(dto, login, ct); return string.Format(SuccessResponse.UpdateSuccessWithCodeAndName, dto.MatrixCode, dto.MatrixTitle); } } catch { if (isNew && an != null) await _autoNumber.RollbackAutoNumber("MSKILLMATRIX", an.StartNumber, login); throw; } } public async Task Delete(int configId, LoginDTO login, CancellationToken ct) { var rows = await _dal.SoftDelete(configId, login.UserId, login, ct); if (rows == 0) throw new Exception(ErrorResponse.DeleteNotFoundMessage); return SuccessResponse.DeleteSuccessMessage; } } }