using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using LCU.API.Internal.RepoApi.Repos.Exceptions; using LCU.API.Internal.RepoApi.Repos.Models; using LCU.API.Internal.RepoApi.Repos.Persistence; using Microsoft.EntityFrameworkCore; using Serilog; namespace LCU.API.Internal.RepoApi.Repos.Repositories { public class EventAlertRepository : BaseRepository, IEventAlertRepository { private const string RepoStatus = "REPO"; private const string O4RStatus = "O4R"; private const int ClosedAccountCutoffDays = 90; private static List _nonRepeatingAlerts = new List { "Credit Adjustment Received", "Debit Adjustment Received", "Notice of Plan to Sell Not Found", "Notice of Repossession Not Found", "RTC Letter Not Found" }; public EventAlertRepository(AppDbContext context) : base(context) { } public async Task> ListAllAsync() { return await _context.EventAlerts.ToListAsync(); } public async Task> ListUnreadAsync() { var result = from alert in _context.EventAlerts join repo in _context.RepoAccounts on alert.AccountNo equals repo.AccountNo join activeStatus in _context.RepoManualStatuses on repo.Status equals activeStatus.Description where activeStatus.WatchForStatusChanges && alert.DateMarkedRead == null select alert; return await result.Distinct().ToListAsync(); } public async Task> ListWithinDateRangeAsync(DateTime start, DateTime end) { return await _context.EventAlerts.Where(e => e.DateAdded >= start && e.DateAdded <= end).ToListAsync(); } public async Task> ListRepoNoAuctionAsync() { var closedDateCutoff = DateTime.Today.Subtract(TimeSpan.FromDays(ClosedAccountCutoffDays)); var accountsInRepo = ( from repo in _context.RepoAccounts where repo.Status.Equals(RepoStatus) && (repo.DateClosed == null || repo.DateClosed > closedDateCutoff) select repo); var accountsInRepoWithAuction = ( from repo in accountsInRepo join auctionAssignment in _context.AuctionAssignments on repo.RepoId equals auctionAssignment.RepoId where auctionAssignment.IsActive == true select repo); var accountsNoAuction = await accountsInRepo.Except(accountsInRepoWithAuction).ToListAsync(); return accountsNoAuction.Select(repo => new EventAlert() { AccountNo = repo.AccountNo, RepoId = repo.RepoId, Message = "Repo No Auction" }).Distinct(); } public async Task> ListRepoNoCompanyAsync() { return await ListStatusNoCompanyAsync(RepoStatus); } public async Task> ListO4rNoCompanyAsync() { return await ListStatusNoCompanyAsync(O4RStatus); } public async Task> ListStatusNoCompanyAsync(string status) { var closedDateCutoff = DateTime.Today.Subtract(TimeSpan.FromDays(ClosedAccountCutoffDays)); var result = from repo in _context.RepoAccounts from collateral in _context.Collaterals.Where(c => c.RepoId == repo.RepoId) from repoCompanySelection in _context.RepoCompanySelections.Where(x => x.CollateralId == collateral.CollateralId).DefaultIfEmpty() where (repoCompanySelection == null || repoCompanySelection.RepoCompanyId == null) && repo.Status.Equals(status) && (repo.DateClosed == null || repo.DateClosed > closedDateCutoff) select new EventAlert { AccountNo = repo.AccountNo, RepoId = repo.RepoId, Message = status + " No Repo Company" }; var temp = await result.Distinct().ToListAsync(); return temp; } public async Task> ListReadyForRetitleAsync() { var result = from collateral in _context.Collaterals join repo in _context.RepoAccounts on collateral.RepoId equals repo.RepoId join auctionAssignmentToCollateral in _context.AuctionAssignmentToCollaterals on collateral.CollateralId equals auctionAssignmentToCollateral.CollateralId join auctionAssignment in _context.AuctionAssignments on auctionAssignmentToCollateral.AuctionAssignmentId equals auctionAssignment.ID from data in Queryable.Where(_context.ImsAutoFileData, ims => auctionAssignment.ID == ims.AuctionAssignmentId || (repo.RepoId == ims.RepoId && auctionAssignment.CollateralVIN == ims.VIN)) where collateral.RetitledInLandmarkName == null && repo.Status.Equals(RepoStatus) && auctionAssignment.IsActive && repo.RedemptionExpiredDate < DateTime.Today select new EventAlert { AccountNo = repo.AccountNo, RepoId = repo.RepoId, Message = "Ready For Retitle" }; return await result.Distinct().ToListAsync(); } public async Task> ListFloorUpdateFailedAsync() { var result = from autoFileData in _context.ImsAutoFileData join repo in _context.RepoAccounts on autoFileData.RepoId equals repo.RepoId join collateral in _context.Collaterals on repo.RepoId equals collateral.RepoId join auctionAssignmentToCollateral in _context.AuctionAssignmentToCollaterals on collateral.CollateralId equals auctionAssignmentToCollateral.CollateralId join auctionAssignment in _context.AuctionAssignments on auctionAssignmentToCollateral.AuctionAssignmentId equals auctionAssignment.ID where ((auctionAssignment.HoldStatus ?? 0) == 0 || (auctionAssignment.HoldUntil ?? DateTime.Now) <= DateTime.Now) && auctionAssignment.RedeemedDate == null && autoFileData.SoldDate == null && (auctionAssignment.FloorPriceResponseCode != null && auctionAssignment.FloorPriceResponseCode != 1) select new EventAlert { AccountNo = repo.AccountNo, RepoId = repo.RepoId, Message = "Floor Update Failed" }; return await result.Distinct().ToListAsync(); } public async Task> ListFloorNeedsSettingAsync() { var result = from data in _context.ImsAutoFileData join repo in _context.RepoAccounts on data.RepoId equals repo.RepoId join collateral in _context.Collaterals on repo.RepoId equals collateral.RepoId join auctionAssignmentToCollateral in _context.AuctionAssignmentToCollaterals on collateral.CollateralId equals auctionAssignmentToCollateral.CollateralId join auctionAssignment in _context.AuctionAssignments on auctionAssignmentToCollateral.AuctionAssignmentId equals auctionAssignment.ID where (auctionAssignment.FloorPrice ?? 0) == 0 && ((auctionAssignment.HoldStatus ?? 0) == 0 || (auctionAssignment.HoldUntil ?? DateTime.Now) <= DateTime.Now) && auctionAssignment.RedeemedDate == null && data.SoldDate == null && data.ScheduledSaleDate != null && data.ScheduledSaleDate < DateTime.Now.AddDays(3) && repo.DateClosed == null select new EventAlert { AccountNo = repo.AccountNo, RepoId = repo.RepoId, Message = "Floor Set Required" }; return await result.Distinct().ToListAsync(); } public async Task AddAsync(EventAlert eventAlert) { if (eventAlert.SubMessage != null && eventAlert.SubMessage.Length > 499) { eventAlert.SubMessage = eventAlert.SubMessage.Substring(0, 499); } if (!IsDuplicateAlert(eventAlert)) { await _context.EventAlerts.AddAsync(eventAlert); } else { throw new DuplicateResourceException("EventAlert"); } } public async Task> AddRangeAsync(IEnumerable eventAlerts) { List filteredEventAlerts = new List(); foreach (EventAlert eventAlert in eventAlerts) { if (eventAlert.SubMessage != null && eventAlert.SubMessage.Length > 499) { eventAlert.SubMessage = eventAlert.SubMessage.Substring(0, 499); } if (!IsDuplicateAlert(eventAlert)) { filteredEventAlerts.Add(eventAlert); } else { Log.Debug($"EventAlertRepository: Valid Alert Already Exists eventAlert: {@eventAlert}." + $" Will Continue without adding this to Event Alerts Context.", eventAlerts, eventAlert ); } } await _context.EventAlerts.AddRangeAsync(filteredEventAlerts); return filteredEventAlerts; } public bool IsDuplicateAlert(EventAlert eventAlert) { var duplicateAlerts = ( from alert in _context.EventAlerts where alert.AccountNo == eventAlert.AccountNo && alert.Message == eventAlert.Message && ( alert.DateMarkedRead == null || alert.DateMarkedRead > DateTime.Now.AddHours(-24) || _nonRepeatingAlerts.Contains(alert.Message) ) select alert ).ToList(); return (duplicateAlerts.Any()); } public async Task FindByIdAsync(int id) { return await _context.EventAlerts.FindAsync(id); } public void Update(EventAlert category) { _context.EventAlerts.Update(category); } public void Remove(EventAlert category) { _context.EventAlerts.Remove(category); } public async Task> ListUnreadByAccountNoAsync(string accountNo) { var results = _context.EventAlerts.Where(x => x.AccountNo == accountNo && x.DateMarkedRead == null); return await results.ToListAsync(); } } }