using Microsoft.EntityFrameworkCore; using ProposalSystem.Application.DTOs; using ProposalSystem.Application.Interfaces; using ProposalSystem.Domain.Entities; using ProposalSystem.Infrastructure.Data; namespace ProposalSystem.Infrastructure.Services; public class SimilarProposalService : ISimilarProposalService { private readonly ProposalDbContext _db; public SimilarProposalService(ProposalDbContext db) { _db = db; } public async Task> GetSimilarProposalsAsync( Guid proposalId, CancellationToken ct = default) { var references = await _db.SimilarProposalReferences .Where(r => r.ProposalId == proposalId) .OrderByDescending(r => r.SimilarityScore) .Take(5) .ToListAsync(ct); var results = new List(); foreach (var reference in references) { var referencedProposal = await _db.Proposals .Include(p => p.LineItems) .FirstOrDefaultAsync(p => p.ProposalNumber == reference.ReferencedLibraryItemId, ct); if (referencedProposal == null) continue; results.Add(new SimilarProposalResponse( referencedProposal.ProposalNumber, referencedProposal.CustomerName, referencedProposal.ServiceCategory.ToString(), reference.SimilarityScore, referencedProposal.TotalBidAmount, referencedProposal.LineItems .OrderBy(li => li.SortOrder) .Select(li => new SimilarLineItemResponse( li.Description, li.Quantity, li.Unit, li.UnitPrice, li.TotalPrice )) .ToList() )); } return results; } public async Task AddReferenceAsync( Guid proposalId, CreateSimilarReferenceRequest request, CancellationToken ct = default) { var reference = new SimilarProposalReference { Id = Guid.NewGuid(), ProposalId = proposalId, ReferencedLibraryItemId = request.ReferencedLibraryItemId, SimilarityScore = request.SimilarityScore, ReferencedAt = DateTime.UtcNow, ReferencedById = Guid.Empty, }; _db.SimilarProposalReferences.Add(reference); await _db.SaveChangesAsync(ct); } }