using Hims.Shared.Library.Enums;

namespace Hims.Infrastructure.Services
{
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;

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

        /// <inheritdoc cref="IValidatorService" />
        public ValidatorServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc />
        public async Task<int> ValidateEmailAsync(string query, string type, int referenceId)
        {
            var accountCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"select count(""AccountId"") from ""Account"" where LOWER(TRIM(""Email"")) = LOWER(TRIM('{query}')) and ""ReferenceId"" <> '{referenceId}' AND ""Email"" != ''");
            switch (type)
            {
                case "Patient":
                    return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PatientId"") FROM ""Patient"" WHERE LOWER(TRIM(""Email"")) = LOWER(TRIM('{query}')) AND ""PatientId"" <> '{referenceId}' AND ""Email"" != '' ");
                case "User":
                    var userResponse = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""UserId"") FROM ""User"" WHERE LOWER(TRIM(""Email"")) = LOWER(TRIM('{query}')) AND ""UserId"" <> '{referenceId}'");
                    return accountCount + userResponse;
                case "Provider":
                    var providersCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderId"") FROM ""Provider"" WHERE LOWER(TRIM(""Email"")) = LOWER(TRIM('{query}')) AND ""ProviderId"" <> '{referenceId}' AND ""Email"" != ''");
                    var usersCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""UserId"") FROM ""User"" WHERE LOWER(TRIM(""Email"")) = LOWER(TRIM('{query}')) AND ""UserId"" <> '{referenceId}' AND ""RoleId"" IN ({(int)Roles.Nurse},{(int)Roles.Receptionist})");
                    return providersCount + usersCount + accountCount;
                default:
                    return 0;
            }
        }

        /// <inheritdoc />
        public async Task<int> ValidateMobileAsync(string query, int countryId, string type, int referenceId)
        {
            var accountCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"select count(""AccountId"") from ""Account"" where ""Mobile"" = '{query}' AND ""CountryId"" = '{countryId}' and ""Mobile"" != '' and ""ReferenceId"" <> '{referenceId}' ");
            switch (type)
            {
                case "Patient":
                    return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PatientId"") FROM ""Patient"" WHERE ""Mobile"" = '{query}' AND ""CountryId"" = '{countryId}' AND ""PatientId"" <> '{referenceId}'");
                case "User":
                    var userCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""UserId"") FROM ""User"" WHERE ""Mobile"" = '{query}' AND ""CountryId"" = '{countryId}' AND ""UserId"" <> '{referenceId}'");
                    return userCount + accountCount;
                case "Provider":
                    var providersCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderId"") FROM ""Provider"" WHERE ""Mobile"" = '{query}' AND ""CountryId"" = '{countryId}' AND ""ProviderId"" <> '{referenceId}' AND ""Mobile"" != ''");
                    var usersCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""UserId"") FROM ""User"" WHERE ""Mobile"" = '{query}' AND ""CountryId"" = '{countryId}' AND ""UserId"" <> '{referenceId}' AND ""RoleId"" IN ({(int)Roles.Nurse},{(int)Roles.Receptionist}) ");
                    return providersCount + usersCount + accountCount;
                default:
                    return 0;
            }
        }

        /// <inheritdoc />
        public Task<int> ValidateNpiAsync(string query, int providerId) =>
            this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(
                $@"SELECT COUNT(""ProviderId"") FROM ""Provider"" WHERE ""NPI"" = '{query}' AND ""ProviderId"" <> '{providerId}'");

        /// <inheritdoc />
        public Task<int> ValidatePharmacyProductAsync(string query, int? pharmacyProductId)
        {
            var where = string.Empty;
            if(pharmacyProductId != null)
            {
                where += $@" and ""PharmacyProductId"" <> {pharmacyProductId}";
            }
            var querys = $@"SELECT count(""PharmacyProductId"") FROM ""PharmacyProduct"" where LOWER(TRIM(""ProductName"")) = LOWER(TRIM('{query}')) {where}";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(querys);
        }

        public async Task<int> ValidateUserNameAsync(string query, string type, int referenceId)
        {
            var accountCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"select count(""AccountId"") from ""Account"" where LOWER(TRIM(""UserName"")) = LOWER(TRIM('{query}')) and ""ReferenceId"" <> '{referenceId}' AND ""UserName"" != ''");
            switch (type)
            {
                case "Patient":
                    return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PatientId"") FROM ""Patient"" WHERE LOWER(TRIM(""UserName"")) = LOWER(TRIM('{query}')) AND ""PatientId"" <> '{referenceId}' AND ""UserName"" != '' ");
                case "User":
                    var userResponse = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(ad.""ReferenceId"") FROM ""Account"" ad LEFT JOIN ""User"" usr on usr.""UserId"" = ad.""ReferenceId"" WHERE LOWER(TRIM(ad.""Email"")) = LOWER(TRIM('{query}')) AND usr.""UserId"" <> '{referenceId}' ");
                    return accountCount + userResponse;
                case "Provider":
                    ///var providersCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderId"") FROM ""Provider"" WHERE LOWER(TRIM(""Email"")) = LOWER(TRIM('{query}')) AND ""ProviderId"" <> '{referenceId}' AND ""UserName"" != ''");
                    var providersCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(ad.""ReferenceId"") FROM ""Account"" ad LEFT JOIN ""User"" usr on usr.""UserId"" = ad.""ReferenceId"" WHERE LOWER(TRIM(ad.""Email"")) = LOWER(TRIM('{query}')) AND usr.""UserId"" <> '{referenceId}' ");
                    ///var usersCount = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""UserId"") FROM ""User"" WHERE LOWER(TRIM(""UserName"")) = LOWER(TRIM('{query}')) AND ""UserId"" <> '{referenceId}' AND ""RoleId"" IN ({(int)Roles.Nurse},{(int)Roles.Receptionist})");
                    var usersCount = 0;
                    return providersCount + usersCount + accountCount;
                default:
                    return 0;
            }
        }
    }
}
