Clear        


                
                    using APP.Domain;
using APP.Models;
using CORE.APP.Models;
using CORE.APP.Services;
using Microsoft.EntityFrameworkCore;

namespace APP.Services
{
    // Inherit from the generic entity service class therefore DbContext injected constructor can be automatically created
    // and entity CRUD (create, read, update, delete) methods in the base class can be invoked.
    public class StoreService : Service<Store>, IService<StoreRequest, StoreResponse>
    {
        public StoreService(DbContext db) : base(db)
        {
        }

        // base virtual Query method is overriden therefore the overriden query can be used in all other methods
        protected override IQueryable<Store> Query(bool isNoTracking = true)
        {
            return base.Query(isNoTracking) // returns Stores DbSet
                .Include(s => s.ProductStores).ThenInclude(ps => ps.Product) // first includes relational ProductStore entities,
                                                                             // then includes relational Product entities of the
                                                                             // ProductStore entities
                .OrderBy(s => s.IsVirtual) // orders ascending by IsVirtual (true or false)
                .ThenBy(s => s.Name); // then applies ascending ordering by Name to the ordered ascending by IsVirtual query

            // Include, ThenInclude, OrderBy, OrderByDescending, ThenBy and ThenByDescending methods can also be used with DbSets.
        }

        public CommandResponse Create(StoreRequest request)
        {
            // s: Store entity delegate. Check if a virtual or physical store with the same name exists.
            if (Query().Any(s => s.Name == request.Name.Trim() && s.IsVirtual == request.IsVirtual))
            {
                // Way 1:
                //return Error((request.IsVirtual ? "Virtual" : "Physical") + " store with the same name exists!");
                // Way 2:
                return Error($"{(request.IsVirtual ? "Virtual" : "Physical")} store with the same name exists!");
            }

            // map the StoreRequest to Store entity
            var entity = new Store
            {
                Name = request.Name.Trim(), // request.Name is required and can't be null
                IsVirtual = request.IsVirtual
            };

            Create(entity); // will add the entity to the Stores DbSet and since save default parameter's value is true, will save changes to the database

            return Success("Store created successfully.", entity.Id);
        }

        public CommandResponse Delete(int id)
        {
            // s: Store entity delegate. Get the Store entity by ID from the Stores table
            var entity = Query(false).SingleOrDefault(s => s.Id == id); // isNoTracking is false for being tracked by EF Core to delete the entity
            if (entity is null)
                return Error("Store not found!");

            // delete the relational ProductStore entities data
            Delete(entity.ProductStores);

            // delete the Store entity data
            Delete(entity);

            return Success("Store deleted successfully.", entity.Id);
        }

        public StoreRequest Edit(int id)
        {
            // get the Store entity by ID from the Stores table
            var entity = Query().SingleOrDefault(s => s.Id == id);
            if (entity is null)
                return null;

            // map the Store entity to StoreRequest and return
            return new StoreRequest
            {
                // assigning entity properties to the response
                Id = entity.Id,
                Name = entity.Name,
                IsVirtual = entity.IsVirtual
            };
        }

        public StoreResponse Item(int id)
        {
            // get the Store entity by ID from the Stores table
            var entity = Query().SingleOrDefault(s => s.Id == id);
            if (entity is null)
                return null;

            // map the Store entity to StoreResponse and return
            return new StoreResponse
            {
                // assigning entity properties to the response
                Id = entity.Id,
                Guid = entity.Guid,
                Name = entity.Name,
                IsVirtual = entity.IsVirtual,

                // assigning custom or formatted properties to the response
                IsVirtualF = entity.IsVirtual ? "Virtual" : "Physical",
                ProductCount = entity.ProductStores.Count,
                Products = string.Join("<br>", entity.ProductStores.Select(ps => ps.Product.Name))
            };
        }

        public List<StoreResponse> List()
        {
            // project the Store entities query to StoreResponse query and return the list
            return Query().Select(entity => new StoreResponse
            {
                // assigning entity properties to the response
                Id = entity.Id,
                Guid = entity.Guid,
                Name = entity.Name,
                IsVirtual = entity.IsVirtual,

                // assigning custom or formatted properties to the response
                IsVirtualF = entity.IsVirtual ? "Virtual" : "Physical",
                ProductCount = entity.ProductStores.Count,
                Products = string.Join("<br>", entity.ProductStores.Select(ps => ps.Product.Name))
            }).ToList();
        }

        public CommandResponse Update(StoreRequest request)
        {
            // s: Store entity delegate. Check if a physical or virtual store excluding the current updated store with the same name exists.
            if (Query().Any(s => s.Id != request.Id && s.Name == request.Name.Trim() && s.IsVirtual == request.IsVirtual))
                return Error($"{(request.IsVirtual ? "Virtual" : "Physical")} store with the same name exists!");

            // get the Store entity by ID from the Stores table
            var entity = Query(false).SingleOrDefault(s => s.Id == request.Id); // isNoTracking is false for being tracked by EF Core to update the entity
            if (entity is null)
                return Error("Store not found!");

            // update retrieved Store entity's properties with request properties
            entity.Name = request.Name.Trim(); // request.Name is required and can't be null
            entity.IsVirtual = request.IsVirtual;

            Update(entity); // will update the entity in the Stores DbSet and since save default parameter's value is true, will save changes to the database

            return Success("Store updated successfully.", entity.Id);
        }
    }
}