namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Entities;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Shared.EntityModels;

    using Hims.Shared.UserModels.DiscountManagement;
    using System.Linq;

    /// <inheritdoc />
    public class DiscountManagementServices : IDiscountManagementService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <inheritdoc cref="IDiscountManagementService" />
        public DiscountManagementServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc/>
        public async Task<int> AddDiscountModule(DiscountModuleModel model)
        {
            var checkIfQuery = $@"Select count(*) FROM ""DiscountModule"" where lower(""ModuleName"") = '{model.ModuleName.ToLower()}'";
            var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
            if (checkIf > 0)
            {
                return -1;
            }

            var module = new DiscountModule
            {
                Icon = model.Icon,
                ModuleName = model.ModuleName,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                Roles = model.Roles
            };
            return await this.unitOfWork.DiscountModules.InsertAsync(module);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateDiscountModule(DiscountModuleModel model)
        {
            var findExisting = await this.unitOfWork.DiscountModules.FindAsync(m => m.DiscountModuleId == model.DiscountModuleId);

            if (findExisting == null)
            {
                return 0;
            }

            findExisting.Icon = model.Icon;

            findExisting.ModifiedBy = model.CreatedBy;
            findExisting.ModifiedDate = DateTime.Now;

            try
            {
                var role = model.Roles.Split(",");
                var oldRoles = findExisting.Roles.Split(",");
                var newRoles = role.Except(oldRoles).ToArray().Concat(oldRoles.Except(role).ToArray()).ToArray();
                if (newRoles.Length > 0)
                {
                    var query = $@"DELETE FROM ""DiscountsPerModule"" WHERE ""DiscountModuleId"" = {findExisting.DiscountModuleId} and ""RoleId"" in ({string.Join(",", newRoles.Select(m => m))})";
                    var res = await this.unitOfWork.Current.ExecuteAsync(query);
                }
                findExisting.Roles = model.Roles;
            }
            catch (Exception)
            {
                return -2;
            }

            return await this.unitOfWork.DiscountModules.UpdateAsync(findExisting);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<DiscountModuleModel>> FetchAllDiscountModulesAsync(DiscountModuleModel model)
        {
            var query = $@"SELECT DM.""DiscountModuleId"", DM.""ModuleName"", DM.""Icon"", DM.""Roles"", DM.""CreatedBy"", DM.""CreatedDate"", DM.""Active"",
			                        DM.""ModifiedBy"", DM.""ModifiedDate"",C.""FullName"" as ""CreatedByName"",CR.""RoleName"" as ""CreatedByRole"",
			                        M.""FullName"" as ""ModifiedByName"",MR.""RoleName"" as ""ModifiedByRole""
	                        FROM ""DiscountModule"" DM
	                        join ""Account"" C on  C.""AccountId"" = DM.""CreatedBy"" 
	                        join ""Role"" CR on CR.""RoleId"" = C.""RoleId""
	                        left join ""Account"" M on  M.""AccountId"" = DM.""ModifiedBy"" 
	                        left join ""Role"" MR on MR.""RoleId"" = M.""RoleId"" order by 1 desc";
            var modules = (await this.unitOfWork.Current.QueryAsync<DiscountModuleModel>(query)).AsList();

            if (modules.Count > 0)
            {
                foreach (var module in modules)
                {
                    module.RoleDiscounts = new List<DiscountsPerModuleModel>();
                    var data = await this.unitOfWork.DiscountsPerModules.FindAllAsync(d => d.DiscountModuleId == module.DiscountModuleId);
                    var list = data?.ToList().Select(m => new DiscountsPerModuleModel
                    {
                        DiscountModuleId = m.DiscountModuleId,
                        AllowedPercentage = m.AllowedPercentage,
                        CreatedBy = m.CreatedBy,
                        DiscountsPerModuleId = m.DiscountsPerModuleId,
                        RoleId = m.RoleId
                    });
                    module.RoleDiscounts = list.ToList();
                }
            }
            return modules;
        }

        /// <inheritdoc/>
        public async Task<int> AddDiscountsPerModuleAsync(DiscountsPerModuleModel model)
        {
            var discounts = new DiscountsPerModule
            {
                AllowedPercentage = model.AllowedPercentage,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                DiscountModuleId = model.DiscountModuleId,
                RoleId = model.RoleId
            };

            return await this.unitOfWork.DiscountsPerModules.InsertAsync(discounts);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateDiscountsPerModuleAsync(DiscountsPerModuleModel model)
        {
            var findExisting = await this.unitOfWork.DiscountsPerModules.FindAsync(d => d.DiscountsPerModuleId == model.DiscountsPerModuleId);

            if (findExisting == null)
            {
                return 0;
            }

            findExisting.AllowedPercentage = model.AllowedPercentage;
            findExisting.ModifiedBy = model.CreatedBy;
            findExisting.ModifiedDate = DateTime.UtcNow.AddMinutes(330);

            return await this.unitOfWork.DiscountsPerModules.UpdateAsync(findExisting);
        }

        /// <inheritdoc/>
        public async Task<DiscountModuleModel> GetModuleDetailsAsync(string moduleName)
        {
            var query = $@"SELECT ""DiscountModuleId"", ""ModuleName"", ""Icon"" FROM ""DiscountModule"" where lower(""ModuleName"") = '{moduleName.ToLower()}'";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<DiscountModuleModel>(query);
        }

        /// <inheritdoc/>
        public async Task<DiscountsPerModuleModel> GetRoleBasedDisocuntOnModule(DiscountsPerModuleModel model)
        {
            var query = $@"SELECT ""DiscountsPerModuleId"", ""DiscountModuleId"", ""RoleId"", ""AllowedPercentage"" FROM ""DiscountsPerModule"" 
		                        where ""DiscountModuleId"" = {model.DiscountModuleId}  and ""RoleId"" = {model.RoleId}";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<DiscountsPerModuleModel>(query);
        }

        /// <inheritdoc />
        public async Task<int> ActivateOrDeactivate(DiscountModuleModel model)
        {
            var query = $@"UPDATE ""DiscountModule"" SET ""ModifiedBy""={model.ModifiedBy}, ""ModifiedDate""=now(), ""Active""= {(bool)model.Active}
	                           WHERE ""DiscountModuleId""= {model.DiscountModuleId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }
    }
}