using ACG6MvcAdHcApi.DataRepository;
using ACG6MvcAdHcApi.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
 
namespace ACG6MvcAdHcApi.BusinessLayer
{
     /// <summary>
     /// Works like the Base class for ProductBusinessLayer class.
     /// ************************************* Do not make changes to this class *************************************
     /// ** Put your additional code in the ProductBusinessLayer class under the BusinessLayer folder. **
     /// *************************************************************************************************************
     /// 
     /// </summary>
     public partial class ProductBusinessLayer : IProductBusinessLayer
     {
         private readonly IProductRepository _productRepository;
         private readonly ISupplierBusinessLayer _supplierBusinessLayer;
         private readonly ICategoryBusinessLayer _categoryBusinessLayer;
 
         /// <summary>
         /// constructor
         /// </summary>
         public ProductBusinessLayer(IProductRepository productRepository, ISupplierBusinessLayer supplierBusinessLayer, ICategoryBusinessLayer categoryBusinessLayer)
         {
             _productRepository = productRepository;
             _supplierBusinessLayer = supplierBusinessLayer;
             _categoryBusinessLayer = categoryBusinessLayer;
         }
 
         /// <summary>
         /// Selects a record by primary key(s)
         /// </summary>
         public async Task<Product> SelectByPrimaryKeyAsync(int productID)
         {
             DataTable dt = await _productRepository.SelectByPrimaryKeyAsync(productID);
 
             // create Product
             if (dt is not null && dt.Rows.Count > 0)
                 return await this.CreateProductFromDataRowAsync(dt.Rows[0]);
 
             return null;
         }
 
         /// <summary>
         /// Gets the total number of records in the Products table
         /// </summary>
         public async Task<intGetRecordCountAsync()
         {
             return await _productRepository.GetRecordCountAsync();
         }
 
         /// <summary>
         /// Gets the total number of records in the Products table by SupplierID
         /// </summary>
         public async Task<intGetRecordCountBySupplierIDAsync(intsupplierID)
         {
             return await _productRepository.GetRecordCountBySupplierIDAsync(supplierID);
         }
 
         /// <summary>
         /// Gets the total number of records in the Products table by CategoryID
         /// </summary>
         public async Task<intGetRecordCountByCategoryIDAsync(intcategoryID)
         {
             return await _productRepository.GetRecordCountByCategoryIDAsync(categoryID);
         }
 
         /// <summary>
         /// Gets the total number of records in the Products table based on search parameters
         /// </summary>
         public async Task<intGetRecordCountDynamicWhereAsync(intproductIDstring productNameintsupplierIDintcategoryIDstring quantityPerUnitdecimalunitPrice, Int16? unitsInStock, Int16? unitsOnOrder, Int16? reorderLevelbooldiscontinued)
         {
             return await _productRepository.GetRecordCountDynamicWhereAsync(productID, productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued);
         }
 
         /// <summary>
         /// Selects records as a collection (List) of Product sorted by the sortByExpression.
         /// </summary>
         public async Task<List<Product>> SelectSkipAndTakeAsync(int rowsint startRowIndexstring sortByExpression)
         {
             sortByExpression = this.GetSortExpression(sortByExpression);
             DataTable dt = await _productRepository.SelectSkipAndTakeAsync(sortByExpression, startRowIndex, rows);
             return await this.GetListOfProduct(dt);
         }
 
         /// <summary>
         /// Selects records by SupplierID as a collection (List) of Product sorted by the sortByExpression starting from the startRowIndex
         /// </summary>
         public async Task<List<Product>> SelectSkipAndTakeBySupplierIDAsync(int rowsint startRowIndexstring sortByExpressionintsupplierID)
         {
             sortByExpression = this.GetSortExpression(sortByExpression);
             DataTable dt = await _productRepository.SelectSkipAndTakeBySupplierIDAsync(sortByExpression, startRowIndex, rows, supplierID);
             return await this.GetListOfProduct(dt);
         }
 
         /// <summary>
         /// Selects records by CategoryID as a collection (List) of Product sorted by the sortByExpression starting from the startRowIndex
         /// </summary>
         public async Task<List<Product>> SelectSkipAndTakeByCategoryIDAsync(int rowsint startRowIndexstring sortByExpressionintcategoryID)
         {
             sortByExpression = this.GetSortExpression(sortByExpression);
             DataTable dt = await _productRepository.SelectSkipAndTakeByCategoryIDAsync(sortByExpression, startRowIndex, rows, categoryID);
             return await this.GetListOfProduct(dt);
         }
 
         /// <summary>
         /// Selects records as a collection (List) of Product sorted by the sortByExpression starting from the startRowIndex, based on the search parameters
         /// </summary>
         public async Task<List<Product>> SelectSkipAndTakeDynamicWhereAsync(intproductIDstring productNameintsupplierIDintcategoryIDstring quantityPerUnitdecimalunitPrice, Int16? unitsInStock, Int16? unitsOnOrder, Int16? reorderLevelbooldiscontinuedint rowsint startRowIndexstring sortByExpression)
         {
             sortByExpression = this.GetSortExpression(sortByExpression);
             DataTable dt = await _productRepository.SelectSkipAndTakeDynamicWhereAsync(productID, productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, sortByExpression, startRowIndex, rows);
             return await this.GetListOfProduct(dt);
         }
 
         /// <summary>
         /// Selects all records as a collection (List) of Product
         /// </summary>
         public async Task<List<Product>> SelectAllAsync()
         {
             DataTable dt = await _productRepository.SelectAllAsync();
             return await this.GetListOfProduct(dt);
         }
 
         /// <summary>
         /// Selects all records as a collection (List) of Product sorted by the sort expression
         /// </summary>
         public async Task<List<Product>> SelectAllAsync(string sortByExpression)
         {
             DataTable dt = await _productRepository.SelectAllAsync();
             List<Product> objProductsList = await this.GetListOfProduct(dt);
             return await this.SortByExpressionAsync(objProductsList, sortByExpression);
         }
 
         /// <summary>
         /// Selects records based on the passed filters as a collection (List) of Product.
         /// </summary>
         public async Task<List<Product>> SelectAllDynamicWhereAsync(intproductIDstring productNameintsupplierIDintcategoryIDstring quantityPerUnitdecimalunitPrice, Int16? unitsInStock, Int16? unitsOnOrder, Int16? reorderLevelbooldiscontinued)
         {
             DataTable dt = await _productRepository.SelectAllDynamicWhereAsync(productID, productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued);
             return await this.GetListOfProduct(dt);
         }
 
         /// <summary>
         /// Selects records based on the passed filters as a collection (List) of Product sorted by the sort expression.
         /// </summary>
         public async Task<List<Product>> SelectAllDynamicWhereAsync(intproductIDstring productNameintsupplierIDintcategoryIDstring quantityPerUnitdecimalunitPrice, Int16? unitsInStock, Int16? unitsOnOrder, Int16? reorderLevelbooldiscontinuedstring sortByExpression)
         {
             DataTable dt = await _productRepository.SelectAllDynamicWhereAsync(productID, productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued);
             List<Product> objProductsList = await this.GetListOfProduct(dt);
             return await this.SortByExpressionAsync(objProductsList, sortByExpression);
         }
 
         /// <summary>
         /// Selects ProductID and ProductName columns for use with a DropDownList web control, ComboBox, CheckedBoxList, ListView, ListBox, etc
         /// </summary>
         public async Task<List<Product>> SelectProductDropDownListDataAsync()
         {
             List<Product> objProductsList = null;
             DataTable dt = await _productRepository.SelectProductDropDownListDataAsync();
 
             // build the list of Products
             if (dt is not null && dt.Rows.Count > 0)
             {
                 objProductsList = new();
 
                 foreach (DataRow dr in dt.Rows)
                 {
                     Product objProduct = new();
                     objProduct.ProductID = (int)dr["ProductID"];
 
                     if(String.IsNullOrEmpty(dr["ProductName"].ToString()))
                         objProduct.ProductName = String.Empty;
                     else
                         objProduct.ProductName = (string)(dr["ProductName"]);
 
                     objProductsList.Add(objProduct);
                 }
             }
 
             return objProductsList;
         }
 
         /// <summary>
         /// Sorts the List<Product >by sort expression
         /// </summary>
         public async Task<List<Product>> SortByExpressionAsync(List<Product> objProductsListstring sortExpression)
         {
             bool isSortDescending = sortExpression.ToLower().Contains(" desc");
 
             if (isSortDescending)
             {
                 sortExpression = sortExpression.Replace(" DESC""");
                 sortExpression = sortExpression.Replace(" desc""");
             }
             else
             {
                 sortExpression = sortExpression.Replace(" ASC""");
                 sortExpression = sortExpression.Replace(" asc""");
             }
 
             switch (sortExpression)
             {
                 case "ProductID":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.ByProductID));
                     break;
                 case "ProductName":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.ByProductName));
                     break;
                 case "SupplierID":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.BySupplierID));
                     break;
                 case "CategoryID":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.ByCategoryID));
                     break;
                 case "QuantityPerUnit":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.ByQuantityPerUnit));
                     break;
                 case "UnitPrice":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.ByUnitPrice));
                     break;
                 case "UnitsInStock":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.ByUnitsInStock));
                     break;
                 case "UnitsOnOrder":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.ByUnitsOnOrder));
                     break;
                 case "ReorderLevel":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.ByReorderLevel));
                     break;
                 case "Discontinued":
                     await Task.Run(() => objProductsList.Sort(ACG6MvcAdHcApi.BusinessLayer.ProductBusinessLayer.ByDiscontinued));
                     break;
                 default:
                     break;
             }
 
             if (isSortDescending)
                 objProductsList.Reverse();
 
             return objProductsList;
         }
 
         /// <summary>
         /// Inserts a new record
         /// </summary>
         public async Task<intInsertAsync(Product objProduct)
         {
             return await _productRepository.InsertAsync(objProduct);
         }
 
         /// <summary>
         /// Updates a record
         /// </summary>
         public async Task UpdateAsync(Product objProduct) =>
             await _productRepository.UpdateAsync(objProduct);
 
         /// <summary>
         /// Deletes a record based on primary key(s)
         /// </summary>
         public async Task DeleteAsync(int productID) =>
             await _productRepository.DeleteAsync(productID);
 
         /// <summary>
         /// Deletes multiple records based on primary keys
         /// </summary>
         public async Task DeleteMultipleAsync(List<Int32> productIDList)
         {
             foreach (var id in productIDList)
             {
                 await _productRepository.DeleteAsync(id);
             }
         }
 
         /// <summary>
         /// Gets the default sort expression when no sort expression is provided
         /// </summary>
         private string GetSortExpression(string sortByExpression)
         {
             // when no sort expression is provided, ProductID is set as the default in ascending order
             // for ascending order, "asc" is not needed, so it is removed
             if (String.IsNullOrEmpty(sortByExpression) || sortByExpression == " asc")
                 sortByExpression = "ProductID";
             else if (sortByExpression.Contains(" asc"))
                 sortByExpression = sortByExpression.Replace(" asc""");
 
             return sortByExpression;
         }
 
         /// <summary>
         /// Gets a List of Products based on the sql script.
         /// </summary>
         /// <param name="sqlParamList">List of SqlParameters</param>
         /// <param name="sql">The SQL script</param>
         /// <returns>List of Products</returns>
         private async Task<List<Product>> GetListOfProduct (DataTable dt)
         {
             List<Product> objProductsList = null;
 
             // build the list of Products
             if (dt != null && dt.Rows.Count > 0)
             {
                 objProductsList = new List<Product>();
 
                 foreach (DataRow dr in dt.Rows)
                 {
                     Product objProduct = await this.CreateProductFromDataRowAsync(dr);
                     objProductsList.Add(objProduct);
                 }
             }
 
             return objProductsList;
         }
 
         /// <summary>
         /// Creates a Product object from Data Row
         /// </summary>
         private async Task<Product> CreateProductFromDataRowAsync(DataRow dr)
         {
             // instantiate the Product model
             Product objProduct = new();
 
             // assign values to the model
             objProduct.ProductID = (int)dr["ProductID"];
             objProduct.ProductName = dr["ProductName"].ToString();
 
             if (dr["SupplierID"] != System.DBNull.Value)
             {
                 int supplierID = (int)dr["SupplierID"];
                 objProduct.SupplierID = supplierID;
                 objProduct.Supplier = await _supplierBusinessLayer.SelectByPrimaryKeyAsync(supplierID);
             }
             else
             {
                 objProduct.SupplierID = null;
                 objProduct.Supplier = null;
             }
 
             if (dr["CategoryID"] != System.DBNull.Value)
             {
                 int categoryID = (int)dr["CategoryID"];
                 objProduct.CategoryID = categoryID;
                 objProduct.Category = await _categoryBusinessLayer.SelectByPrimaryKeyAsync(categoryID);
             }
             else
             {
                 objProduct.CategoryID = null;
                 objProduct.Category = null;
             }
 
             if (dr["QuantityPerUnit"] != System.DBNull.Value)
                 objProduct.QuantityPerUnit = dr["QuantityPerUnit"].ToString();
             else
                 objProduct.QuantityPerUnit = null;
 
             if (dr["UnitPrice"] != System.DBNull.Value)
                 objProduct.UnitPrice = (decimal)dr["UnitPrice"];
             else
                 objProduct.UnitPrice = null;
 
             if (dr["UnitsInStock"] != System.DBNull.Value)
                 objProduct.UnitsInStock = (Int16)dr["UnitsInStock"];
             else
                 objProduct.UnitsInStock = null;
 
             if (dr["UnitsOnOrder"] != System.DBNull.Value)
                 objProduct.UnitsOnOrder = (Int16)dr["UnitsOnOrder"];
             else
                 objProduct.UnitsOnOrder = null;
 
             if (dr["ReorderLevel"] != System.DBNull.Value)
                 objProduct.ReorderLevel = (Int16)dr["ReorderLevel"];
             else
                 objProduct.ReorderLevel = null;
             objProduct.Discontinued = (bool)dr["Discontinued"];
 
             return objProduct;
         }
 
         /// <summary>
         /// Compares ProductID used for sorting
         /// </summary>
         public static Comparison<Product> ByProductID = delegate(Product x, Product y)
         {
             return x.ProductID.CompareTo(y.ProductID);
         };
 
         /// <summary>
         /// Compares ProductName used for sorting
         /// </summary>
         public static Comparison<Product> ByProductName = delegate(Product x, Product y)
         {
             string value1 = x.ProductName ?? String.Empty;
             string value2 = y.ProductName ?? String.Empty;
             return value1.CompareTo(value2);
         };
 
         /// <summary>
         /// Compares SupplierID used for sorting
         /// </summary>
         public static Comparison<Product> BySupplierID = delegate(Product x, Product y)
         {
             return Nullable.Compare(x.SupplierID, y.SupplierID);
         };
 
         /// <summary>
         /// Compares CategoryID used for sorting
         /// </summary>
         public static Comparison<Product> ByCategoryID = delegate(Product x, Product y)
         {
             return Nullable.Compare(x.CategoryID, y.CategoryID);
         };
 
         /// <summary>
         /// Compares QuantityPerUnit used for sorting
         /// </summary>
         public static Comparison<Product> ByQuantityPerUnit = delegate(Product x, Product y)
         {
             string value1 = x.QuantityPerUnit ?? String.Empty;
             string value2 = y.QuantityPerUnit ?? String.Empty;
             return value1.CompareTo(value2);
         };
 
         /// <summary>
         /// Compares UnitPrice used for sorting
         /// </summary>
         public static Comparison<Product> ByUnitPrice = delegate(Product x, Product y)
         {
             return Nullable.Compare(x.UnitPrice, y.UnitPrice);
         };
 
         /// <summary>
         /// Compares UnitsInStock used for sorting
         /// </summary>
         public static Comparison<Product> ByUnitsInStock = delegate(Product x, Product y)
         {
             return Nullable.Compare(x.UnitsInStock, y.UnitsInStock);
         };
 
         /// <summary>
         /// Compares UnitsOnOrder used for sorting
         /// </summary>
         public static Comparison<Product> ByUnitsOnOrder = delegate(Product x, Product y)
         {
             return Nullable.Compare(x.UnitsOnOrder, y.UnitsOnOrder);
         };
 
         /// <summary>
         /// Compares ReorderLevel used for sorting
         /// </summary>
         public static Comparison<Product> ByReorderLevel = delegate(Product x, Product y)
         {
             return Nullable.Compare(x.ReorderLevel, y.ReorderLevel);
         };
 
         /// <summary>
         /// Compares Discontinued used for sorting
         /// </summary>
         public static Comparison<Product> ByDiscontinued = delegate(Product x, Product y)
         {
             return x.Discontinued.CompareTo(y.Discontinued);
         };
 
     }
}