using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using SkillManagementDAL.CustomCode.SkillProcessStageMap; using SkillManagementDAL.DTO.Skill; using SkillManagementDAL.DTO.SkillProcessStageMap; using System.Text.Json; namespace SkillManagementBLL.SkillProcessStageMap { public class SkillProcessStageMapBLL : ISkillProcessStageMapBLL { private readonly ISkillProcessStageMapDAL _dal; private readonly AutoNumber _autoNumber; public SkillProcessStageMapBLL(ISkillProcessStageMapDAL dal, AutoNumber autoNumber) { _dal = dal; _autoNumber = autoNumber; } public async Task GetBySkill(int skillId, LoginDTO login, CancellationToken ct) => await _dal.GetBySkill(skillId, login, ct); public async Task Save(IEnumerable maps, int skillId, LoginDTO login, CancellationToken ct) { if (skillId == 0) throw new ArgumentException("SkillId is required."); var mapList = maps.ToList(); if (!mapList.Any()) return "No mappings provided."; // Resolve MinLevelRequired from SkillLevelId where the frontend // sends the MSKILLLEVEL.SLEVELID but not the SLNO (1-4). foreach (var m in mapList) { if (m.SkillLevelId != 0 && (m.MinLevelRequired == 0 || m.MinLevelRequired > 4)) m.MinLevelRequired = await _dal.GetSlNoBySkillLevelId(m.SkillLevelId, login); } // Identify new maps (MapId = 0) var newMaps = mapList.Where(m => m.MapId == 0).ToList(); if (newMaps.Any()) { var an = await _autoNumber.GetNumberAsync(newMaps.Count, "MROUTINGSKILL", login); int nextId = an.StartNumber; foreach (var m in newMaps) { m.MapId = nextId++; m.SkillId = skillId; } } // Call DAL layer to handle insert/update/delete var affectedRows = await _dal.Save(mapList, skillId, login, ct); // mapList only carries IDs/codes from the client — SkillName/RoutingName // are join-only display fields, so re-fetch the saved rows to get them // for the response message. var savedJson = await _dal.GetBySkill(skillId, login, ct); var saved = System.Text.Json.JsonSerializer.Deserialize>( savedJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); var first = saved?.FirstOrDefault(); return string.Format(SuccessResponse.MapSuccessWithSkillAndRouting, first?.SkillName, first?.RoutingName); } public async Task GetSelectList(CriteriaDTO criteriaDTO, LoginDTO login, CancellationToken ct) => await _dal.GetSelectList(criteriaDTO, login, ct); public async Task DeleteById(int mapId, LoginDTO login, CancellationToken ct) { var rows = await _dal.DeleteById(mapId, login, ct); if (rows == 0) throw new Exception(ErrorResponse.DeleteNotFoundMessage); return SuccessResponse.DeleteSuccessMessage; } public async Task GetSkillProcessStageMapList(int firstNumber, int maxResult, CriteriaDTO criteriaDTO, LoginDTO login, CancellationToken ct = default) { // ── VALIDATION ─────────────────────────────────────────── 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}"); // ── FETCH DATA ─────────────────────────────────────────── bool isAllData = firstNumber == -1 && maxResult == -1; List data = isAllData ? await _dal.GetAllList(login, ct) : await _dal.GetPagedList(firstNumber, maxResult, login, ct); // ── SERIALIZE (KEY CHANGE) ──────────────────────────────── var json = JsonSerializer.Serialize(data); return json; } } }