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 Hims.Domain.EntityModels;
    using Shared.EntityModels;
    using Shared.UserModels.Filters;

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

        /// <inheritdoc cref="IChargeCategoryService" />
        public ChargeCategoryService(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc />
        public async Task<int> AddAsync(ChargeCategoryModel model)
        {
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ChargeCategoryId"") FROM ""ChargeCategory"" WHERE TRIM(UPPER(""ChargeCategoryName"")) = '{model.ChargeCategoryName.ToUpper().Trim()}'");
            if (checkIf > 0)
            {
                return -1;
            }

            var chargeCategory = new ChargeCategory
            {
                Active = true,
                ChargeCategoryName = model.ChargeCategoryName,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                Default = false
            

            };
            return await this.unitOfWork.ChargeCategorys.InsertAsync(chargeCategory);

        }

        /// <inheritdoc />
        public Task<int> DeleteAsync(int chargeCategoryId)
        {
            throw new NotImplementedException();
        }

        /// <inheritdoc />
        public Task<IEnumerable<ChargeCategoryModel>> FetchAsync(ChargeCategoryModel model)
        {
            var where = " WHERE 1 = 1 ";
            if (model.ChargeCategoryId > 0)
            {
                where += $@" AND cc.""ChargeCategoryId"" = {model.ChargeCategoryId}";
            }
            if (!string.IsNullOrEmpty(model.ChargeCategoryName))
            {
                where += $@" and cc.""ChargeCategoryName"" = '{model.ChargeCategoryName}' ";
            }
            
            var query = $@"SELECT COUNT (*) OVER () AS ""TotalItems"",cc.""ChargeCategoryId"",cc.""Active"",cc.""ChargeCategoryName"",cc.""Default"",CA.""FullName"" AS ""CreatedByName"" , MA.""FullName"" AS ""ModifiedByName"" , cc.""CreatedDate"",cc.""ModifiedDate""
                                       FROM ""ChargeCategory"" cc
                                       left Join ""Account"" CA ON CA.""AccountId"" = cc.""CreatedBy""
                                       Left Join ""Account"" MA ON MA.""AccountId"" = cc.""ModifiedBy""   
                                         {where}
                                    group by cc.""ChargeCategoryId"",CA.""FullName"", MA.""FullName""
                                 Order by ""ChargeCategoryId"" DESC ";
            if (model.PageIndex <= 0)
            {
                return this.unitOfWork.Current.QueryAsync<ChargeCategoryModel>(query);
            }
            model.PageIndex -= 1;
            query += " LIMIT " + model.PageSize + " OFFSET " + (model.PageIndex * model.PageSize);
            return this.unitOfWork.Current.QueryAsync<ChargeCategoryModel>(query);
        }

        /// <inheritdoc />
        public async Task<int> ModifyStatusAsync(ChargeCategoryModel model)
        {
            var Check = await this.unitOfWork.ChargeCategorys.FindAsync(p => p.ChargeCategoryId == model.ChargeCategoryId);
            if (Check.Default == true && model.Active == false)
            {
                return -2;
            }
            var query = $@"UPDATE ""ChargeCategory""
	                           SET ""ModifiedBy""={model.CreatedBy}, ""ModifiedDate""=now(), ""Active""= {model.Active}
	                           WHERE ""ChargeCategoryId""= {model.ChargeCategoryId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(ChargeCategoryModel model)
        {

            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>($@"Select count(*) from ""ChargeCategory"" where lower(""ChargeCategoryName"") = '{model.ChargeCategoryName.ToLower()}' and ""ChargeCategoryId"" <>{model.ChargeCategoryId}");

                if (checkIf > 0)
                {
                    return -1;
                }
                var record = await this.unitOfWork.ChargeCategorys.FindAsync(p => p.ChargeCategoryId == model.ChargeCategoryId);
                if (record == null)
                {
                    return 0;
                }

                var charge = new ChargeCategory
                {
                    ChargeCategoryId = record.ChargeCategoryId,
                    ChargeCategoryName = model.ChargeCategoryName,
                    Default = record.Default,
                    ModifiedBy = model.CreatedBy,
                    ModifiedDate = DateTime.Now,
                    Active = record.Active,
                    //LocationId = Convert.ToInt32(locationId)
                };
                var charg = await this.unitOfWork.ChargeCategorys.UpdateAsync(charge, transaction);

                if (charg == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                transaction.Commit();
                return charg;
            }

        }

        /// <inheritdoc />
        public Task<IEnumerable<ChargeCategoryModel>> FetchChargeCategoryMastersAsync()
        {
            var query = $@"SELECT DISTINCT ""ChargeCategoryId"",  ""ChargeCategoryName"", ""Default""
                        FROM ""ChargeCategory"" where ""Active"" is true ORDER BY ""ChargeCategoryName"" ASC";
            return this.unitOfWork.Current.QueryAsync<ChargeCategoryModel>(query);
        }

        /// <inheritdoc />
        public Task<IEnumerable<ChargeCategoryModel>> FetchRoomChargeAsync(ChargeCategoryModel model)
        {
            var where = " WHERE 1 = 1 ";
            if (model.ChargeCategoryId > 0)
            {
                where += $@" and  RC.""ChargeCategoryId"" = {model.ChargeCategoryId} ";
            }
            if (model.LocationId > 0)
            {
                where += $@"  and  L.""LocationId"" = {model.LocationId}";
            }
            var query = $@"SELECT count(RC.""RoomChargeId"") over() as TotalItems, RC.""RoomChargeId"",RC.""Cost"", RC.""Active"",RC.""CreatedDate"",CA.""FullName"" AS ""CreatedByName"" ,CC.""ChargeCategoryName"",RC.""ChargeCategoryId"",
                            RC.""ModifiedBy"",RC.""ModifiedDate"",MA.""FullName"" As ""ModifiedByName"",  L.""Name"" as ""LocationNames"",RC.""LocationId""
                        FROM ""RoomCharge"" RC
                        left join ""ChargeCategory"" CC on CC.""ChargeCategoryId""=RC.""ChargeCategoryId""
                        left Join ""Account"" CA on CA.""AccountId"" = RC.""CreatedBy""
                        left join ""Account"" MA on MA.""AccountId""=RC.""ModifiedBy""
                        left Join ""Location"" L on L.""LocationId""=RC.""LocationId"" {where}
                    ORDER BY ""RoomChargeId"" ASC";

            if (model.PageIndex <= 0)
            {
                return this.unitOfWork.Current.QueryAsync<ChargeCategoryModel>(query);
            }

            model.PageIndex -= 1;
            query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);
            return this.unitOfWork.Current.QueryAsync<ChargeCategoryModel>(query);

        }

        /// <inheritdoc />
        public async Task<int> InsertChargetoCategoryAsync(ChargeCategoryModel model)
        {
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""RoomChargeId"") FROM ""RoomCharge"" WHERE ""ChargeCategoryId"" = {model.ChargeCategoryId} and ""LocationId""= {model.LocationId}");
            if (checkIf > 0)
            {
                return -1;
            }

            var roomCharge = new RoomCharge
            {
                ChargeCategoryId = (int)model.ChargeCategoryId,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                LocationId = model.LocationId,
                Cost = (double)model.Cost
            };
            return await this.unitOfWork.RoomCharges.InsertAsync(roomCharge);

        }

        /// <inheritdoc />
        public async Task<int> UpdateChargetoCategoryAsync(ChargeCategoryModel model)
        {

            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""RoomChargeId"") FROM ""RoomCharge"" WHERE ""ChargeCategoryId"" = {model.ChargeCategoryId} and ""LocationId""= {model.LocationId} and ""Cost"" ={model.Cost}");
            if (checkIf > 0)
            {
                return -1;
            }
            var record = await this.unitOfWork.RoomCharges.FindAsync(p => p.RoomChargeId == model.RoomChargeId);
            if (record == null)
            {
                return 0;
            }
            record.ChargeCategoryId = (int)model.ChargeCategoryId;
            record.LocationId = model.LocationId;
            record.Cost = (double)model.Cost;
            record.ModifiedBy = model.CreatedBy;
            record.ModifiedDate = DateTime.Now;
            
            

            return await this.unitOfWork.RoomCharges.UpdateAsync(record);
        }

        /// <inheritdoc />
        public async Task<int> MakeDefaultChargeCategoryAsync(ChargeCategoryModel model)
        {
            var Check = await this.unitOfWork.ChargeCategorys.FindAsync(p => p.ChargeCategoryId == model.ChargeCategoryId);
            if (Check.Active == false)
            {
                return -2;
            }
            var query = $@"update ""ChargeCategory"" set ""Default"" = false ; update ""ChargeCategory"" set ""Default"" = true where ""ChargeCategoryId"" = {model.ChargeCategoryId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        public async Task<int> ModifyStatusRoomAsync(ChargeCategoryModel model)
        {
            var query = $@"UPDATE ""RoomCharge""
	                           SET ""ModifiedBy""={model.CreatedBy}, ""ModifiedDate""=now(), ""Active""= {model.Active}
	                           WHERE ""ChargeCategoryId""= {model.ChargeCategoryId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }
    }
    }
