namespace GrossesMitainesAPI.Controllers; #region Dependencies using Microsoft.AspNetCore.Mvc; using GrossesMitainesAPI.Models; using System.Linq; using GrossesMitainesAPI.Data; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Cors; using GrossesMitainesAPI.Services; using System.Collections.Immutable; #endregion [EnableCors("_myAllowSpecificOrigins"), ApiController, Route("api/[controller]"), Authorize(AuthenticationSchemes = "Identity.Application")] public class SearchController : Controller { #region Constants private const int PREVIEW = 4; #endregion #region DI Fields private readonly ILogger _logger; private readonly InventoryContext _context; private readonly DatabaseCacheService _cache; private IQueryable? _searchCache = null; #endregion #region Ctor public SearchController(ILogger logger, InventoryContext context, DatabaseCacheService cache) { _logger = logger; _context = context; _cache = cache; if (_cache.isOk()) _searchCache = _cache.queryCache(); } #endregion #region API Methods [EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Search"), AllowAnonymous] public IEnumerable Get(string query, bool? preview, string? filterPrice, string? filterState, string? order = "Relevance") { if (preview.HasValue && preview == true) return _searchCache is null ? _context.Products.Where(x => x.Title.Contains(query)).Take(PREVIEW).Select(x => new ProductViewModel(x)).ToList() : _searchCache.Where(x => x.Title.Contains(query)).Take(PREVIEW).Select(x => new ProductViewModel(x)).ToList(); return Search(query, filterPrice, filterState, order); } #endregion #region Internal Methods private List Search(string query, string? filterPrice, string? filterState, string? order) { List products = new(); query = query.Trim(); try { query = query.ToLower(); IQueryable ret; if (_searchCache is null) { _logger.LogError(8, "Erreur de cache."); ret = _context.Products.AsQueryable().Select(x => new ProductViewModel(x)); } else ret = _searchCache.Select(x => new ProductViewModel(x)); switch (filterPrice) { case "PriceUnder20": ret = ret.Where(x => x.Price < 20); break; case "Price20to49": ret = ret.Where(x => x.Price >= 20 && x.Price < 50); break; case "Price50to99": ret = ret.Where(x => x.Price >= 50 && x.Price < 100); break; case "PriceOver100": ret = ret.Where(x => x.Price >= 100); break; default: break; } switch (filterState) { case "isAvailable": ret = ret.Where(x => x.Status == ProductModel.States.Available); break; case "isUnavailable": ret = ret.Where(x => x.Status == ProductModel.States.Unavailable); break; case "isBackOrder": ret = ret.Where(x => x.Status == ProductModel.States.BackOrder); break; ; case "isClearance": ret = ret.Where(x => x.Status == ProductModel.States.Clearance); break; case "isDiscontinued": ret = ret.Where(x => x.Status == ProductModel.States.Discontinued); break; case "isPromoted": ret = ret.Where(x => x.Status == ProductModel.States.Clearance || x.Status == ProductModel.States.Promotion); break; default: break; } switch (order) { case "Relevance": List title = new(), desc = new(), cat = new(); foreach (ProductViewModel prod in ret.ToList()) { string sTitle = prod.Title.Replace(",", " ").ToLower() + " ", sCat = " " + prod.Category.ToLower() + " ", sDesc = prod.Description.Replace(".", " ").Replace(",", " ").ToLower() + " "; if (sTitle.StartsWith(query)) products.Add(prod); else if (sTitle.Contains(" " + query)) title.Add(prod); else if (sDesc.Contains(" " + query)) desc.Add(prod); else if (sCat.Contains(" " + query)) cat.Add(prod); } products.AddRange(title); products.AddRange(desc); products.AddRange(cat); break; case "Price": ret = ret.OrderBy(x => x.Status == ProductModel.States.Promotion || x.Status == ProductModel.States.Clearance ? x.PromoPrice : x.Price); goto default; case "PriceDesc": ret = ret.OrderByDescending(x => x.Status == ProductModel.States.Promotion || x.Status == ProductModel.States.Clearance ? x.PromoPrice : x.Price); goto default; case "Title": ret = ret.OrderBy(x => x.Title); goto default; case "TitleDesc": ret = ret.OrderByDescending(x => x.Title); goto default; case "Category": ret = ret.OrderBy(x => x.Category); goto default; case "CategoryDesc": ret = ret.OrderByDescending(x => x.Category); goto default; default: foreach (ProductViewModel prod in ret.ToList()) { string sTitle = prod.Title.Replace(",", " ").ToLower() + " ", sCat = " " + prod.Category.ToLower() + " ", sDesc = prod.Description.Replace(".", " ").Replace(",", " ").ToLower() + " "; if (sTitle.StartsWith(query) || sTitle.Contains(" " + query + " ") || sDesc.StartsWith(query) || sDesc.Contains(" " + query + " ") || sCat.Contains(" " + query + " ")) products.Add(prod); } break; } } catch (Exception e) { _logger.LogError(8, e.Message); return new List(); } return products; } #endregion }