using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using GB5Shared.Validation; using KmsDAL.CustomCode.KmArtifact; using KmsDAL.CustomCode.KmContent; using KmsDAL.DTO.KmArtifact; using KmsDAL.DTO.KmDiscovery; using KmsDAL.DTO.KmContent; namespace KmsBLL.KmArtifact { public class KmArtifactBLL : IKmArtifactBLL { private readonly IKmArtifactDAL _dal; private readonly IKmContentDAL _contentDal; private readonly AutoNumber _autoNumber; private readonly IValidation _validation; public KmArtifactBLL(IKmArtifactDAL dal, IKmContentDAL contentDal, AutoNumber autoNumber, IValidation validation) { _dal = dal; _contentDal = contentDal; _autoNumber = autoNumber; _validation = validation; } public async Task GetKmArtifact(int artifactId, LoginDTO login, CancellationToken ct) => await _dal.GetKmArtifact(artifactId, login, ct); public async Task GetKmArtifacts(int domainId, byte governanceState, byte artifactType, int page, int pageSize, LoginDTO login, CancellationToken ct) => await _dal.GetKmArtifacts(domainId, governanceState, artifactType, page, pageSize, login, ct); public async Task SaveKmArtifact(KmArtifactDTO dto, LoginDTO login, CancellationToken ct) { await _validation.NotEmpty(dto.ArtifactCode, nameof(dto.ArtifactCode)); await _validation.NotEmpty(dto.Title, nameof(dto.Title)); if (dto.DomainId <= 0) throw new ArgumentException("DomainId is required."); var duplicateCount = await _dal.GetKmArtifactCodeCount(dto.ArtifactCode, dto.ArtifactId, login, ct); if (duplicateCount > 0) throw new InvalidOperationException($"Artifact code '{dto.ArtifactCode}' already exists."); dto.TenantId = login.ClientId; bool isNew = dto.ArtifactId == 0; if (isNew) { // Allocate ID for artifact + content items int contentCount = dto.Contents?.Count ?? 0; int totalRequired = 1 + (contentCount > 0 ? contentCount : 1); var autoNum = await _autoNumber.GetNumberAsync(totalRequired, "KMARTIFACT", login); int nextId = autoNum.StartNumber; dto.ArtifactId = nextId++; dto.CreatedById = login.UserId; dto.ModifiedById = login.UserId; dto.ParentArtifactId = dto.ParentArtifactId <= 0 ? -1 : dto.ParentArtifactId; dto.OwnerUserId = dto.OwnerUserId <= 0 ? login.UserId : dto.OwnerUserId; dto.ReviewerUserId = dto.ReviewerUserId <= 0 ? -1 : dto.ReviewerUserId; dto.ExtractionJobId = dto.ExtractionJobId <= 0 ? -1 : dto.ExtractionJobId; await _dal.SaveKmArtifact(dto, login, ct); // Save primary content if provided if (dto.Contents?.Count > 0) { short slno = 1; foreach (var c in dto.Contents) { var content = new KmContentDTO { ContentId = nextId++, ArtifactId = dto.ArtifactId, Slno = slno++, ContentBody = c.ContentBody, ContentType = string.IsNullOrEmpty(c.ContentType) ? "Text" : c.ContentType, LanguageCode = string.IsNullOrEmpty(c.LanguageCode) ? "en" : c.LanguageCode, IsPrimary = slno == 2 ? (byte)1 : (byte)0, ChunkIndex = 0, ChunkTotal = 1 }; await _contentDal.SaveKmContent(content, login, ct); } } return $"{SuccessResponse.SaveSuccessMessage} {dto.ArtifactId}"; } else { dto.ModifiedById = login.UserId; await _dal.UpdateKmArtifact(dto, login, ct); return $"{SuccessResponse.UpdateSuccessMessage} {dto.ArtifactId}"; } } public async Task DeleteKmArtifact(int artifactId, LoginDTO login, CancellationToken ct) { var state = await _dal.GetArtifactCurrentState(artifactId, login, ct); if (state == null) throw new InvalidOperationException("Artifact not found."); if (state.GovernanceState != 0 && state.GovernanceState != 4) throw new InvalidOperationException("Only Draft or Retired artifacts can be deleted."); await _contentDal.DeleteKmContentByArtifact(artifactId, login, ct); await _dal.DeleteKmArtifact(artifactId, login, ct); return SuccessResponse.DeleteSuccessMessage; } public async Task UpdateQdrantPoint(KmQdrantUpdateDTO dto, LoginDTO login, CancellationToken ct) { await _dal.UpdateQdrantPoint(dto.ArtifactId, dto.QdrantPointId, dto.EmbeddingModel, login, ct); return SuccessResponse.UpdateSuccessMessage; } } }