using FluentValidation; using Microsoft.EntityFrameworkCore; using Somnia.GuestLog.Infrastructure; using Somnia.GuestLog.Models.DTOs; using Somnia.GuestLog.Models.Entities; using Somnia.GuestLog.Utils; namespace Somnia.GuestLog.Services; public class GuestDocumentService( ILogger logger, IDbContextFactory contextFactory, IValidator dtoValidator ) : IGuestDocumentService { public async Task CreateDocumentAsync(GuestDocumentDTO dto) { ArgumentNullException.ThrowIfNull(dto); var valResult = dtoValidator.Validate(dto); if (!valResult.IsValid) { logger.LogWarning("GuestDocumentService - CreateDocument: Dto validation failed. Fix the errors: {errorList}", valResult.Errors); return false; } //Dto must be valid, so null warings shouldn't matter. GuestAddress addressItem = new() { Address = dto.Address, AddressCity = dto.AddressCity, AddressProvince = dto.AddressProvince, AddressState = dto.AddressState, AddressCountry = dto.AddressCountry!, ZipCode = dto.ZipCode, }; GuestDocument dbItem = new() { DocumentType = dto.DocumentType!, DocumentNum = dto.DocumentNum!, IssueDate = DateOnly.FromDateTime(dto.IssueDate!.Value), SupportNum = dto.SupportNum, Nationality = dto.Nationality!, Name = dto.Name!, Surname = dto.Surname!, Surname2 = dto.Surname2, BirthDate = DateOnly.FromDateTime(dto.BirthDate!.Value), Gender = dto.Gender, PhoneNumber = dto.PhoneNumber, EmailAddress = dto.EmailAddress, AddressDetails = addressItem, CreateTime = DateTime.UtcNow, UpdateTime = DateTime.UtcNow, }; try { using var dbContext = contextFactory.CreateDbContext(); await dbContext.AddAsync(dbItem); await dbContext.SaveChangesAsync(); logger.LogInformation("GuestDocumentService - CreateDocument: GuestDocument Created: '{id}'", dbItem.GetFullKey()); return true; } catch (Exception ex) { logger.LogError(ex, "GuestDocumentService - CreateDocument: Error creating GuestDocument: '{id}'", dbItem.GetFullKey()); return false; } } public Task UpdateDocumentAsync(GuestDocumentDTO dto) { throw new NotImplementedException(); } public Task DeleteDocumentAsync(GuestDocumentDTO dto) { if (dto.DocumentType is null || dto.DocumentNum is null) { throw new InvalidOperationException("GuestDocumentService - DeleteDocument: A DTO without key can't be deleted!"); } return DeleteDocumentAsync(dto.DocumentType, dto.DocumentNum); } public async Task DeleteDocumentAsync(string docType, string docNum) { using var dbContext = contextFactory.CreateDbContext(); GuestDocument? dbItem = await dbContext.GuestDocuments.FindAsync(docType, docNum); if (dbItem is null) { logger.LogWarning("GuestDocumentService - DeleteDocument: Error deleting GuestDocument. Entity not found with key: '{key}-{key2}'", docType, docNum); return false; } try { dbContext.GuestDocuments.Remove(dbItem); await dbContext.SaveChangesAsync(); logger.LogInformation("GuestDocumentService - DeleteDocument: GuestDocument deleted: '{id}'", dbItem.GetFullKey()); return true; } catch (Exception ex) { logger.LogError(ex, "GuestDocumentService - CreateDocument: Error deleting GuestDocument: '{id}'", dbItem.GetFullKey()); return false; } } public async Task GetDtoByIdAsync(string docType, string docNum) { using var dbContext = contextFactory.CreateDbContext(); GuestDocument? dbItem = await dbContext.GuestDocuments.FindAsync(docType, docNum); return dbItem is not null ? GetDtoFromDb(dbItem) : null; } public async Task> GetDtoListAsync() { using var dbContext = contextFactory.CreateDbContext(); var dbList = await dbContext.GuestDocuments .OrderByDescending(e => e.UpdateTime) .ToListAsync(); return dbList.Select(x => GetDtoFromDb(x)); } /// /// Get GuestDocumentDTO from DB with the given filters. /// Result count can be limited for perfomance reasons. /// /// Filters to use /// Result count. Set to 0 for unlimited results /// Filtered GuestDocumentDTO result list public async Task> GetDtoListByFilterAsync(GuestDocFilterDTO filter, int limit = 0) { using var dbContext = contextFactory.CreateDbContext(); var query = dbContext.GuestDocuments.AsQueryable(); query = query.WhereIf(!string.IsNullOrEmpty(filter.DocumentType), e => e.DocumentType == filter.DocumentType); query = query.WhereIf(!string.IsNullOrEmpty(filter.DocumentNumber), e => e.DocumentNum == filter.DocumentNumber); query = query.WhereIf(!string.IsNullOrEmpty(filter.Name), e => EF.Functions.Like(e.Name, filter.Name)); query = query.WhereIf(!string.IsNullOrEmpty(filter.Surname), e => EF.Functions.Like(e.Surname, filter.Surname)); query = query.OrderByDescending(e => e.UpdateTime); if (limit > 0) { query = query.Take(limit); } var dbList = await query.ToListAsync(); return dbList.Select(x => GetDtoFromDb(x)); } public GuestDocumentDTO GetDtoFromDb(GuestDocument dbItem) { return new() { DocumentType = dbItem.DocumentType, DocumentNum = dbItem.DocumentNum, IssueDate = dbItem.IssueDate.ToDateTime(TimeOnly.MinValue), SupportNum = dbItem.SupportNum, Nationality = dbItem.Nationality, Name = dbItem.Name, Surname = dbItem.Surname, Surname2 = dbItem.Surname2, BirthDate = dbItem.BirthDate.ToDateTime(TimeOnly.MinValue), Gender = dbItem.Gender, PhoneNumber = dbItem.PhoneNumber, EmailAddress = dbItem.EmailAddress, Address = dbItem.AddressDetails?.Address ?? "", AddressCity = dbItem.AddressDetails?.AddressCity ?? "", AddressProvince = dbItem.AddressDetails?.AddressProvince ?? "", AddressState = dbItem.AddressDetails?.AddressState ?? "", AddressCountry = dbItem.AddressDetails?.AddressCountry! ?? "", ZipCode = dbItem.AddressDetails?.ZipCode ?? "", CreateTime = dbItem.CreateTime, UpdateTime = dbItem.UpdateTime, }; } }