using System;
using System.Collections.Generic;
using Dapper;
using Hims.Domain.Entities;

namespace Hims.Infrastructure.Services
{
    using System.Threading.Tasks;
    using Hims.Domain.Repositories.UnitOfWork;
    using Hims.Domain.Services;
    using Shared.UserModels.ChargeManagement;

    /// <summary> The chat service.</summary>
    public class ChargeManagementService : IChargeManagementService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <inheritdoc cref="IChatService" />
        public ChargeManagementService(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;


        public async Task<int> InsertAsync(InsertModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();
            if (model.DepartmentId == 0)
            {
                var query = $@"SELECT ""DepartmentId"" from ""Department"" WHERE UPPER(TRIM(""DepartmentName"")) = UPPER(TRIM('{model.DepartmentName}'))";
                model.DepartmentId = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(query, transaction);

                if (model.DepartmentId == 0)
                {
                    model.DepartmentId = await this.unitOfWork.Departments.InsertAsync(new Department
                    {
                        Active = true,
                        CreatedDate = DateTime.Now,
                        CreatedBy = model.CreatedBy,
                        DepartmentName = model.DepartmentName
                    }, transaction);

                    if (model.DepartmentId <= 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
            }

            if (model.ChargeGroupId == 0)
            {
                var query = $@"SELECT ""ChargeGroupId"" from ""ChargeGroup"" WHERE ""DepartmentId"" = {model.DepartmentId} AND UPPER(TRIM(""ChargeGroupName"")) = UPPER(TRIM('{model.ChargeGroupName}'))";
                model.ChargeGroupId = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(query, transaction);

                if (model.ChargeGroupId == 0)
                {
                    model.ChargeGroupId = await this.unitOfWork.ChargeGroups.InsertAsync(new ChargeGroup
                    {
                        Active = true,
                        CreatedDate = DateTime.Now,
                        CreatedBy = model.CreatedBy,
                        DepartmentId = model.DepartmentId,
                        ChargeGroupName = model.ChargeGroupName
                    }, transaction);

                    if (model.ChargeGroupId <= 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
            }

            var checkQuery = $@"SELECT ""ChargeId"" from ""Charge"" WHERE ""ChargeGroupId"" = {model.ChargeGroupId} AND UPPER(TRIM(""ChargeName"")) = UPPER(TRIM('{model.ChargeName}'))";
            var chargeId = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(checkQuery, transaction);

            if (chargeId != 0)
            {
                transaction.Rollback();
                return -2;
            }

            var response = await this.unitOfWork.Charges.InsertAsync(new Charge
            {
                Active = true,
                CreatedDate = DateTime.Now,
                CreatedBy = model.CreatedBy,
                ChargeGroupId = model.ChargeGroupId,
                ChargeName = model.ChargeName,
                ModulesMasterId=model.ModulesMasterId,
                //Cost = model.Cost,
                //OpCost = model.OpCost,
                RepeatTypeId = model.RepeatTypeId
            }, transaction);

            if (response <= 0)
            {
                transaction.Rollback();
                return -1;
            }

            transaction.Commit();
            return response;
        }

        public async Task<int> UpdateAsync(UpdateModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();
            if (model.DepartmentId == 0)
            {
                var query = $@"SELECT ""DepartmentId"" from ""Department"" WHERE UPPER(TRIM(""DepartmentName"")) = UPPER(TRIM('{model.DepartmentName}'))";
                model.DepartmentId = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(query, transaction);

                if (model.DepartmentId == 0)
                {
                    model.DepartmentId = await this.unitOfWork.Departments.InsertAsync(new Department
                    {
                        Active = true,
                        CreatedDate = DateTime.Now,
                        CreatedBy = model.CreatedBy,
                        DepartmentName = model.DepartmentName
                    }, transaction);

                    if (model.DepartmentId <= 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
            }

            if (model.ChargeGroupId == 0)
            {
                var query = $@"SELECT ""ChargeGroupId"" from ""ChargeGroup"" WHERE ""DepartmentId"" = {model.DepartmentId} AND UPPER(TRIM(""ChargeGroupName"")) = UPPER(TRIM('{model.ChargeGroupName}'))";
                model.ChargeGroupId = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(query, transaction);

                if (model.ChargeGroupId == 0)
                {
                    model.ChargeGroupId = await this.unitOfWork.ChargeGroups.InsertAsync(new ChargeGroup
                    {
                        Active = true,
                        CreatedDate = DateTime.Now,
                        CreatedBy = model.CreatedBy,
                        DepartmentId = model.DepartmentId,
                        ChargeGroupName = model.ChargeGroupName
                    }, transaction);

                    if (model.ChargeGroupId <= 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
            }

            // Update Charge Group
            var chargeGroup = await this.unitOfWork.ChargeGroups.FindAsync(x => x.ChargeGroupId == model.ChargeGroupId, transaction);
            if (chargeGroup.DepartmentId != model.DepartmentId)
            {
                chargeGroup.DepartmentId = model.DepartmentId;
                chargeGroup.ModifiedBy = model.CreatedBy;
                chargeGroup.ModifiedDate = DateTime.Now;
                var chargeGroupUpdateResponse = await this.unitOfWork.ChargeGroups.UpdateAsync(chargeGroup, transaction);
                if (chargeGroupUpdateResponse <= 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }

            var charge = await this.unitOfWork.Charges.FindAsync(x => x.ChargeId == model.ChargeId, transaction);
            charge.ChargeGroupId = model.ChargeGroupId;
            charge.RepeatTypeId = model.RepeatTypeId;
            //charge.Cost = model.Cost;
            //charge.OpCost = model.OpCost;
            charge.ChargeName = model.ChargeName;
            charge.ModifiedBy = model.CreatedBy;
            charge.ModifiedDate = DateTime.Now;

            var chargeUpdateResponse = await this.unitOfWork.Charges.UpdateAsync(charge, transaction);
            if (chargeUpdateResponse <= 0)
            {
                transaction.Rollback();
                return -1;
            }

            var count = await this.unitOfWork.Charges.CountAsync(x => x.ChargeGroupId == model.OldChargeGroupId, transaction);
            if (count <= 0)
            {
                var deleteResponse = await this.unitOfWork.ChargeGroups.DeleteAsync(x => x.ChargeGroupId == model.OldChargeGroupId, transaction);
                if (!deleteResponse)
                {
                    transaction.Rollback();
                    return -1;
                }
            }

            transaction.Commit();
            return chargeUpdateResponse;
        }

        public async Task<IEnumerable<ViewModel>> FetchAsync(FilterModel model)
        {
            var where = $"WHERE 1 = 1 ";

            if (!string.IsNullOrEmpty(model.Department))
            {
                where += $@"AND d.""DepartmentName"" ilike '{model.Department}' ";
            }

            if (!string.IsNullOrEmpty(model.ChargeGroup))
            {
                where += $@"AND g.""ChargeGroupName"" ilike '{model.ChargeGroup}' ";
            }

            if (!string.IsNullOrEmpty(model.Charge))
            {
                where += $@"AND c.""ChargeName"" ilike '{model.Charge}' ";
            }
            if (!string.IsNullOrEmpty(model.Term))
            {
                where += $@"AND(lower(d.""DepartmentName"") ilike '%{model.Term.ToLower()}%' OR lower(g.""ChargeGroupName"") ilike '%{model.Term.ToLower()}%' OR lower(c.""ChargeName"") ilike '%{model.Term}%')";
            }
            var query = $@"SELECT
                            COUNT(c.""ChargeId"") OVER() AS ""TotalItems"",
	                        d.""DepartmentId"",
	                        d.""DepartmentName"",
	                        g.""ChargeGroupId"",
	                        g.""ChargeGroupName"",
	                        c.""ChargeId"",
	                        c.""ChargeName"",
	                        c.""Active"",
	                        c.""RepeatTypeId"",
	                        t.""RepeatTypeName"",
	                        c.""AutomaticTypeId"",
	                        a.""Name"" AS ""AutomaticTypeName"",
	                        c.""ModulesMasterId"",
	                        c.""ChargeTypeId""
                        FROM
	                        ""Department"" d
	                        JOIN ""ChargeGroup"" G ON G.""DepartmentId"" = d.""DepartmentId""
	                        JOIN ""Charge"" C ON C.""ChargeGroupId"" = G.""ChargeGroupId""
	                        LEFT JOIN ""RepeatType"" t on t.""RepeatTypeId"" = c.""RepeatTypeId""
	                        LEFT JOIN ""AutomaticType"" a on a.""AutomaticTypeId"" = c.""AutomaticTypeId"" {where}
                            ORDER BY  d.""DepartmentName"", g.""ChargeGroupName"", c.""ChargeName""";
            if (model.PageSize != null && model.PageIndex != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
                query += $@" limit {model.PageSize} offset {model.PageIndex * model.PageSize}";
            }
            //model.PageIndex -= 1;
            //query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);

            var response = await this.unitOfWork.Current.QueryAsync<ViewModel>(query);
            return response;
        }

        public async Task<IEnumerable<MastersViewModel>> FetchMastersAsync()
        {

            var query = $@"SELECT
	                        d.""DepartmentId"",
	                        d.""DepartmentName"",
	                        g.""ChargeGroupId"",
	                        g.""ChargeGroupName"",
	                        c.""ChargeId"",
	                        c.""ChargeName""
                        FROM
	                        ""Department"" d
	                        JOIN ""ChargeGroup"" G ON G.""DepartmentId"" = d.""DepartmentId""
	                        JOIN ""Charge"" C ON C.""ChargeGroupId"" = G.""ChargeGroupId""";
            var response = await this.unitOfWork.Current.QueryAsync<MastersViewModel>(query);
            return response;
        }
    }
}
