using System.Linq;

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

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

        /// <inheritdoc cref="IRoleService" />
        public RoleServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc />
        public Task<IEnumerable<RoleModel>> FetchAsync(RoleFilterModel model)
        {
            var where = " WHERE 1 = 1 ";
            if (!string.IsNullOrEmpty(model.RoleName))
            {
                where += $@" AND TRIM(UPPER(""RoleName"")) = '{model.RoleName.Trim().ToUpper()}'";
            }
            if (model.RoleId > 0)
            {
                where += $@" and  R.""RoleId"" ={model.RoleId} ";
            }

            if (model.Active != null)
            {
                where += $@" AND R.""Active"" IS {((bool)model.Active ? "TRUE" : "FALSE")}";
            }

            var query = $@"select count(R.""RoleId"") over() as ""TotalItems"", R.""RoleId"", R.""RoleName"", R.""Active"", R.""CreatedBy"", R.""CreatedDate"",

                                R.""ModifiedBy"", R.""ModifiedDate"",
		                        C.""FullName"" as ""CreatedByName"", CR.""RoleName"" as ""CreatedByRole"",M.""FullName"" as ""ModifiedByName"", MR.""RoleName"" as ""ModifiedByRole""
                             FROM ""Role"" R
                             left join ""Account"" C on C.""AccountId"" = R.""CreatedBy""
                             join ""Role"" CR on CR.""RoleId"" = C.""RoleId""
                             left join ""Account"" M on M.""AccountId"" = R.""ModifiedBy""
                             left join ""Role"" MR on MR.""RoleId"" = M.""RoleId""
                                {where} 
                             order by R.""CreatedDate"" desc";

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

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



        /// <inheritdoc />
        public async Task<int> AddAsync(RoleModel model)
        {
            try
            {
                var transaction = this.unitOfWork.BeginTransaction();
                var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""RoleId"") FROM ""Role"" WHERE TRIM(UPPER(""RoleName"")) = '{model.RoleName.ToUpper().Trim()}'", transaction);
                if (checkIf > 0)
                {
                    return -1;
                }

                var role = new Role
                {
                    Active = true,
                    RoleName = model.RoleName,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now
                };

                var roleId = await this.unitOfWork.Roles.InsertAsync(role, transaction);

                if (roleId > 0)
                {
                    var patientDashboard = this.unitOfWork.Menu.Find(x => x.Url == "/app/advance-dashboard/view", transaction);
                    var access = new MenuAccess
                    {
                        RoleId = roleId,
                        IsFullAccess = false,
                        InitialRouteMenuId = patientDashboard.MenuId
                    };

                    var accessResponse = await this.unitOfWork.MenuAccess.InsertAsync(access, transaction);
                    if (accessResponse <= 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }

                    var query = $@"SELECT ""MenuId"" FROM ""Menu"" WHERE ""MainPage"" = 'Patients' ";
                    var menuIds = await this.unitOfWork.Current.QueryAsync<int>(query, transaction);
                    var menuRelationships = menuIds.Select(id => new MenuRelationship { RoleId = roleId, MenuId = id }).ToList();

                    var menuResponse = await this.unitOfWork.MenuRelationship.BulkInsertAsync(menuRelationships, transaction);
                    if (menuResponse <= 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }

                    transaction.Commit();
                    return roleId;

                }

                transaction.Rollback();
                return 0;
            }
            catch (Exception)
            {
                return 0;
            }
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(RoleModel model)
        {
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""RoleId"") FROM ""Role"" WHERE TRIM(UPPER(""RoleName"")) = '{model.RoleName.ToUpper().Trim()}' AND ""RoleId"" <> {model.RoleId}");
            if (checkIf > 0)
            {
                return -1;
            }

            var role = await this.unitOfWork.Roles.FindAsync(m => m.RoleId == model.RoleId);
            role.RoleName = model.RoleName;
            role.Active = true;
            role.ModifiedBy = model.ModifiedBy;
            role.ModifiedDate = DateTime.Now;
            return await this.unitOfWork.Roles.UpdateAsync(role);
        }

        /// <inheritdoc />
        public Task<int> DeleteAsync(int roleId)
        {
            var query = $@"update ""Role"" set ""Active"" = false WHERE ""RoleId""= {roleId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public async Task<int> ActivateOrDeactivateTest(RoleModel model)
        {
            var query = $@"UPDATE ""Role"" SET ""ModifiedBy""={model.CreatedBy}, ""ModifiedDate""=now(), ""Active""= {model.Active}
	                           WHERE ""RoleId""= {model.RoleId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

    }
}