Clear        


                
                    #nullable disable
using APP.Models;
using APP.Services;
using CORE.APP.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;

// Generated from Custom MVC Template.

namespace MVC.Controllers
{
    [Authorize] // Only authenticated users can execute the actions of the controller.
    public class ProductsController : Controller
    {
        // Service injections:
        private readonly IService<ProductRequest, ProductResponse> _productService;
        private readonly IService<CategoryRequest, CategoryResponse> _categoryService;

        /* Can be uncommented and used for many to many relationships, "entity" may be replaced with the related entity name in the controller and views. */
        private readonly IService<StoreRequest, StoreResponse> _StoreService;

        public ProductsController(
			IService<ProductRequest, ProductResponse> productService
            , IService<CategoryRequest, CategoryResponse> categoryService

            /* Can be uncommented and used for many to many relationships, "entity" may be replaced with the related entity name in the controller and views. */
            , IService<StoreRequest, StoreResponse> StoreService
        )
        {
            _productService = productService;
            _categoryService = categoryService;

            /* Can be uncommented and used for many to many relationships, "entity" may be replaced with the related entity name in the controller and views. */
            _StoreService = StoreService;
        }

        private void SetViewData()
        {
            /* 
            ViewBag and ViewData are the same collection (dictionary).
            They carry extra data other than the model from a controller action to its view, or between views.
            */

            // Related items service logic to set ViewData (Id and Name parameters may need to be changed in the SelectList constructor according to the model):
            ViewData["CategoryId"] = new SelectList(_categoryService.List(), "Id", "Title");

            /* Can be uncommented and used for many to many relationships, "entity" may be replaced with the related entity name in the controller and views. */
            ViewBag.StoreIds = new MultiSelectList(_StoreService.List(), "Id", "Name");
        }

        private void SetTempData(string message, string key = "Message")
        {
            /*
            TempData is used to carry extra data to the redirected controller action's view.
            */

            TempData[key] = message;
        }

        // GET: Products
        public IActionResult Index()
        {
            // Get collection service logic:
            var list = _productService.List();
            return View(list); // return response collection as model to the Index view
        }

        // GET: Products/Details/5
        public IActionResult Details(int id)
        {
            // Get item service logic:
            var item = _productService.Item(id);
            return View(item); // return response item as model to the Details view
        }

        // GET: Products/Create
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
                                     // Overrides the Authorize defined for the controller.
        public IActionResult Create()
        {
            SetViewData(); // set ViewData dictionary to carry extra data other than the model to the view
            return View(); // return Create view with no model
        }

        // POST: Products/Create
        [HttpPost, ValidateAntiForgeryToken]
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
                                     // Overrides the Authorize defined for the controller.
        public IActionResult Create(ProductRequest product)
        {
            if (ModelState.IsValid) // check data annotation validation errors in the request
            {
                // Insert item service logic:
                var response = _productService.Create(product);
                if (response.IsSuccessful)
                {
                    SetTempData(response.Message); // set TempData dictionary to carry the message to the redirected action's view
                    return RedirectToAction(nameof(Details), new { id = response.Id }); // redirect to Details action with id parameter as response.Id route value
                }
                ModelState.AddModelError("", response.Message); // to display service error message in the validation summary of the view
            }
            SetViewData(); // set ViewData dictionary to carry extra data other than the model to the view
            return View(product); // return request as model to the Create view
        }

        // GET: Products/Edit/5
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
                                     // Overrides the Authorize defined for the controller.
        public IActionResult Edit(int id)
        {
            // Get item to edit service logic:
            var item = _productService.Edit(id);
            SetViewData(); // set ViewData dictionary to carry extra data other than the model to the view
            return View(item); // return request as model to the Edit view
        }

        // POST: Products/Edit
        [HttpPost, ValidateAntiForgeryToken]
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
                                     // Overrides the Authorize defined for the controller.
        public IActionResult Edit(ProductRequest product)
        {
            if (ModelState.IsValid) // check data annotation validation errors in the request
            {
                // Update item service logic:
                var response = _productService.Update(product);
                if (response.IsSuccessful)
                {
                    SetTempData(response.Message); // set TempData dictionary to carry the message to the redirected action's view
                    return RedirectToAction(nameof(Details), new { id = response.Id }); // redirect to Details action with id parameter as response.Id route value
                }
                ModelState.AddModelError("", response.Message); // to display service error message in the validation summary of the view
            }
            SetViewData(); // set ViewData dictionary to carry extra data other than the model to the view
            return View(product); // return request as model to the Edit view
        }

        // GET: Products/Delete/5
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
                                     // Overrides the Authorize defined for the controller.
        public IActionResult Delete(int id)
        {
            // Get item to delete service logic:
            var item = _productService.Item(id);
            return View(item); // return response item as model to the Delete view
        }

        // POST: Products/Delete
        [HttpPost, ValidateAntiForgeryToken, ActionName("Delete")]
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
                                     // Overrides the Authorize defined for the controller.
        public IActionResult DeleteConfirmed(int id)
        {
            // Delete item service logic:
            var response = _productService.Delete(id);
            SetTempData(response.Message); // set TempData dictionary to carry the message to the redirected action's view
            return RedirectToAction(nameof(Index)); // redirect to the Index action
        }



        // Filtering:
        // GET: Products/List
        public IActionResult List()
        {
            // get all products
            var list = _productService.List();

            // get categories for the categories drop down list (select HTML tag without multiple attribute)
            var categorySelectList = new SelectList(_categoryService.List(), "Id", "Title");

            // get stores for the stores list box (select HTML tag with multiple attribute)
            var storeMultiSelectList = new MultiSelectList(_StoreService.List(), "Id", "Name");

            // create the view model to be sent to the view
            var viewModel = new ProductsIndexViewModel
            {
                List = list,
                Filter = new ProductQueryRequest(), // filter object with no filter criteria
                CategorySelectList = categorySelectList,
                StoreMultiSelectList = storeMultiSelectList
            };

            // send the view model to the view as the model
            return View(viewModel);
        }

        // POST: Products/List
        [HttpPost, ValidateAntiForgeryToken]
        public IActionResult List(ProductsIndexViewModel viewModel)
        {
            // cast to the concrete service type to access the overloaded List method with filter query request parameter
            var list = (_productService as ProductService).List(viewModel.Filter); // get filtered products by the view model's filter request

            // get categories for the categories drop down list as request's CategoryId value selected (select HTML tag without multiple attribute)
            var categorySelectList = new SelectList(_categoryService.List(), "Id", "Title", viewModel.Filter.CategoryId);

            // get stores for the stores list box as request's StoreIds values selected (select HTML tag with multiple attribute)
            var storeMultiSelectList = new MultiSelectList(_StoreService.List(), "Id", "Name", viewModel.Filter.StoreIds);

            // update the view model to be sent to the view, no need to update the Filter property because it is received from the view with data
            viewModel.List = list;
            viewModel.CategorySelectList = categorySelectList;
            viewModel.StoreMultiSelectList = storeMultiSelectList;

            // send the view model to the view as the model
            return View(viewModel);
        }
	}
}