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

    using Shared.EntityModels;
    using Shared.Library.Enums;
    using Shared.UserModels.Filters;

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

        /// <summary>
        /// The amazon s 3 configuration.
        /// </summary>
        private readonly IAmazonS3Configuration amazonS3Configuration;

        /// <inheritdoc cref="IProviderService" />
        public ProviderBankAccountServices(IUnitOfWork unitOfWork, IAmazonS3Configuration amazonS3Configuration)
        {
            this.unitOfWork = unitOfWork;
            this.amazonS3Configuration = amazonS3Configuration;
        }

        /// <inheritdoc />
        public async Task<ProviderBankAccountModel> FindAsync(int providerId)
        {
            var where = $@" WHERE pba.""Active"" IS TRUE AND pba.""ProviderId"" = {providerId}";
            var query = $@"SELECT * FROM ""ProviderBankAccount"" pba {where} ";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<ProviderBankAccountModel>(query);
        }

        /// <inheritdoc />
        public Task<IEnumerable<ProviderModel>> FetchAsync(ProviderFilterModel model)
        {
            var where = $@"WHERE prv.""Active"" IS TRUE ";

            if (!string.IsNullOrEmpty(model.FullName))
            {
                where += $@" AND prv.""FullName"" ILIKE '%{model.FullName}%' ";
            }

            if (!string.IsNullOrEmpty(model.Email))
            {
                where += $@" AND prv.""Email"" ILIKE '%{model.Email}%' ";
            }

            if (!string.IsNullOrEmpty(model.Mobile))
            {
                where += $@" AND prv.""Mobile"" ILIKE '%{model.Mobile}%' ";
            }

            if (!string.IsNullOrEmpty(model.NPI))
            {
                where += $@" AND prv.""NPI"" ILIKE '%{model.NPI}%' ";
            }

            if (model.CountryId != null)
            {
                where += $@" AND prv.""CountryId"" = '{model.CountryId}' ";
            }

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

            if (!string.IsNullOrEmpty(model.CreatedDate))
            {
                where += $@" AND prv.""CreatedDate""::DATE = '{model.CreatedDate}'::DATE ";
            }

            var query = $@"SELECT Count(prv.""ProviderId"") OVER() AS ""TotalItems"", prv.""Guid"", prv.""ProviderId"", act.""AccountId"", prv.""FullName"", prv.""NPI"", prv.""CountryId"",
                                ctr.""CountryCode"", prv.""Email"", prv.""Mobile"", prv.""CreatedDate"", prv.""DateOfBirth"", prv.""Age"", prv.""Experience"",
								prv.""Gender"", prv.""ApprovalStatus"", prv.""ApprovedDate"", prv.""RejectedComments"", prv.""RejectedDate"",
                                (CASE WHEN prv.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', prv.""Guid"", '/', prv.""ThumbnailUrl"") ELSE NULL END) AS ""ThumbnailUrl""
                                FROM ""Provider"" prv
                                Left JOIN ""Account"" act ON act.""ReferenceId"" = prv.""ProviderId"" AND act.""RoleId"" = '{(int)Roles.Provider}' AND act.""Active"" IS TRUE
                                LEFT JOIN ""Country"" ctr ON ctr.""CountryId"" = prv.""CountryId"" AND ctr.""Active"" IS TRUE
                                {where}
                                ORDER BY prv.""ProviderId"" DESC";

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

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

        /// <inheritdoc />
        public async Task<int> UpdateAsync(ProviderBankAccountModel model)
        {
            var checkIf = await this.CheckProviderBankAccountAsync(model.Mobile, model.Email, model.ProviderId);
            if (checkIf != 0)
            {
                return checkIf;
            }

            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var providerBankAccount = await this.unitOfWork.ProviderBankAccounts.FindAsync(m => m.ProviderBankAccountId == model.ProviderBankAccountId);
                providerBankAccount.FullName = model.FullName;
                providerBankAccount.AccountNumber = model.AccountNumber;
                providerBankAccount.IFSCCode = model.IFSCCode;
                providerBankAccount.Email = model.Email;
                providerBankAccount.Mobile = model.Mobile;
                providerBankAccount.Percentage = model.Percentage;
                providerBankAccount.ModifiedBy = model.ModifiedBy;
                providerBankAccount.ModifiedDate = DateTime.UtcNow;

                var updated = await this.unitOfWork.ProviderBankAccounts.UpdateAsync(providerBankAccount);
                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                transaction.Commit();
                return updated;
            }
        }

        /// <inheritdoc />
        public async Task<int> AddAsync(ProviderBankAccountModel model)
        {
            var checkIf = await this.CheckProviderBankAccountAsync(model.Mobile, model.Email, model.ProviderId);
            if (checkIf != 0)
            {
                return checkIf;
            }

            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var providerBankAccount = new ProviderBankAccount
                {
                    AccountNumber = model.AccountNumber,
                    ProviderId = model.ProviderId,
                    IFSCCode = model.IFSCCode,
                    Percentage = model.Percentage,
                    FullName = model.FullName,
                    Email = model.Email,
                    Mobile = model.Mobile,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.UtcNow,
                    Active = true
                };

                providerBankAccount.ProviderBankAccountId = await this.unitOfWork.ProviderBankAccounts.InsertAsync(providerBankAccount);
                if (providerBankAccount.ProviderBankAccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                transaction.Commit();
                return providerBankAccount.ProviderBankAccountId;
            }
        }

        /// <inheritdoc />
        public Task<int> DeleteAsync(int providerId)
        {
            var query = $@"DELETE FROM ""Provider"" WHERE ""ProviderId""= '{providerId}'; 
                           DELETE FROM ""Account"" WHERE ""ReferenceId""= '{providerId}' AND ""RoleId"" = '{(int)Roles.Provider}';";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <summary>
        /// The check provider async.
        /// </summary>
        /// <param name="mobile">
        /// The mobile.
        /// </param>
        /// <param name="email">
        /// The email.
        /// </param>
        /// <param name="providerId">
        /// The provider Id.
        /// </param>
        /// <returns>
        /// The <see cref="int"/>.
        /// </returns>
        private async Task<int> CheckProviderBankAccountAsync(string mobile, string email, int providerId)
        {
            int checkIf;
            if (!string.IsNullOrEmpty(email))
            {
                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderBankAccountId"") FROM ""ProviderBankAccount"" WHERE TRIM(UPPER(""Email"")) = '{email.ToUpper().Trim()}' AND  ""ProviderId"" <> '{providerId}'");
                if (checkIf > 0)
                {
                    return -1;
                }
            }

            if (!string.IsNullOrEmpty(mobile))
            {
                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderBankAccountId"") FROM ""ProviderBankAccount"" WHERE ""Mobile"" = '{mobile}' AND ""ProviderId"" <> '{providerId}'");
                if (checkIf > 0)
                {
                    return -2;
                }
            }

            return 0;
        }
    }
}
