using Data.SeaHavenIndustries; using FluentValidation; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.DTOs; using SeaHaven.Services.Interfaces; using SeaHaven.Services.Validation; namespace SeaHaven.Services.Implementation { /// /// Vendor service implementation /// Contains business logic, validation, and orchestration for Vendor operations /// public class VendorService : IVendorService { private readonly IVendorDataService _vendorDataService; private readonly ICreateVendorValidation _createValidator; private readonly IUpdateVendorValidation _updateValidator; public VendorService( IVendorDataService vendorDataService, ICreateVendorValidation createValidator, IUpdateVendorValidation updateValidator) { _vendorDataService = vendorDataService; _createValidator = createValidator; _updateValidator = updateValidator; } public async Task GetVendorByIdAsync(int id) { var vendor = await _vendorDataService.GetByIdWithDetailsAsync(id); return vendor == null ? null : MapToDTO(vendor); } public async Task GetVendorByIdWithDetailsAsync(int id) { var vendor = await _vendorDataService.GetByIdWithDetailsAsync(id); return vendor == null ? null : MapToDTO(vendor); } public async Task> GetAllVendorsAsync() { var vendors = await _vendorDataService.GetAllAsync(); return vendors.Select(MapToDTO); } public async Task> GetVendorsPagedAsync( int page, int pageSize, string? search = null, bool? isActive = true, IReadOnlyCollection? companies = null, IReadOnlyCollection? trades = null, IReadOnlyCollection? locations = null, IReadOnlyCollection? jobBuckets = null) { var (items, totalCount) = await _vendorDataService.GetPagedAsync( page, pageSize, search, isActive, companies, trades, locations, jobBuckets); return new PagedResult { Items = items.Select(MapToDTO).ToList(), TotalCount = totalCount, Page = page, PageSize = pageSize }; } public async Task CreateVendorAsync(CreateVendorDTO dto, string userId) { var validationResult = await _createValidator.ValidateAsync(dto); if (!validationResult.IsValid) { throw new ValidationException(validationResult.Errors); } var vendor = new Vendor { CompanyName = dto.Name, ContactName = dto.ContactName, Email = dto.Email, Phone = dto.Phone, CompanyPhone = dto.CompanyPhone, Address = dto.Address, City = dto.City, State = dto.State, Zip = dto.Zipcode, TradeSpecialties = dto.TradeSpecialties, GoogleMapsUrl = dto.GoogleMapsUrl, Notes = dto.Notes, IsActive = dto.IsActive, CreatedDate = DateTime.UtcNow, createdby = userId }; var created = await _vendorDataService.AddAsync(vendor); return MapToDTO(created); } public async Task UpdateVendorAsync(int id, UpdateVendorDTO dto, string userId) { var validationResult = await _updateValidator.ValidateAsync(dto); if (!validationResult.IsValid) { throw new ValidationException(validationResult.Errors); } var vendor = await _vendorDataService.GetByIdAsync(id); if (vendor == null) throw new InvalidOperationException($"Vendor with ID {id} not found"); if (dto.Name != null) vendor.CompanyName = dto.Name; if (dto.ContactName != null) vendor.ContactName = dto.ContactName; if (dto.Email != null) vendor.Email = dto.Email; if (dto.Phone != null) vendor.Phone = dto.Phone; if (dto.CompanyPhone != null) vendor.CompanyPhone = dto.CompanyPhone; if (dto.Address != null) vendor.Address = dto.Address; if (dto.City != null) vendor.City = dto.City; if (dto.State != null) vendor.State = dto.State; if (dto.Zipcode != null) vendor.Zip = dto.Zipcode; if (dto.TradeSpecialties != null) vendor.TradeSpecialties = dto.TradeSpecialties; if (dto.GoogleMapsUrl != null) vendor.GoogleMapsUrl = dto.GoogleMapsUrl; if (dto.Notes != null) vendor.Notes = dto.Notes; if (dto.IsActive.HasValue) vendor.IsActive = dto.IsActive.Value; vendor.LastModificationTime = DateTime.UtcNow; if (int.TryParse(userId, out int userIdInt)) vendor.LastModifierUserId = userIdInt; await _vendorDataService.UpdateAsync(vendor); return MapToDTO(vendor); } public async Task DeleteVendorAsync(int id, string userId) { var vendor = await _vendorDataService.GetByIdAsync(id); if (vendor == null) throw new InvalidOperationException($"Vendor with ID {id} not found"); vendor.IsActive = false; vendor.LastModificationTime = DateTime.UtcNow; if (int.TryParse(userId, out int userIdInt)) vendor.LastModifierUserId = userIdInt; await _vendorDataService.UpdateAsync(vendor); } public async Task VendorExistsAsync(int id) { return await _vendorDataService.ExistsAsync(id); } public async Task GetTotalVendorCountAsync() { return await _vendorDataService.CountAsync(); } private VendorDTO MapToDTO(Vendor vendor) { return new VendorDTO { Id = vendor.Id, Name = vendor.CompanyName, ContactName = vendor.ContactName, Email = vendor.Email, Phone = vendor.Phone, CompanyPhone = vendor.CompanyPhone, Address = vendor.Address, City = vendor.City, State = vendor.State, Zipcode = vendor.Zip, TradeSpecialties = vendor.TradeSpecialties, GoogleMapsUrl = vendor.GoogleMapsUrl, Notes = vendor.Notes, IsActive = vendor.IsActive, TotalJobs = vendor.Dispatches == null ? vendor.TotalJobs : CountDistinctWorkOrders(vendor) }; } private static int CountDistinctWorkOrders(Vendor vendor) { if (vendor.Dispatches == null) return 0; return vendor.Dispatches .SelectMany(dispatch => { var linked = dispatch.DispatchWorkOrders?.Select(item => item.WorkOrderId) ?? Enumerable.Empty(); return dispatch.WorkOrderId.HasValue ? linked.Append(dispatch.WorkOrderId.Value) : linked; }) .Distinct() .Count(); } } }