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

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

        /// <inheritdoc cref="ICountryService" />
        public CountryServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc />
        public Task<IEnumerable<CountryModel>> FetchAsync(CountryFilterModel model)
        {
            var where = " WHERE 1 = 1 ";
            if (!string.IsNullOrEmpty(model.FullName))
            {
                where += $@" AND TRIM(UPPER(""CountryName"")) = '{model.FullName.Trim().ToUpper()}'";
            }

            if (!string.IsNullOrEmpty(model.ISOCode))
            {
                where += $@" AND ""ISOCode"" = '{model.ISOCode}'";
            }

            if (!string.IsNullOrEmpty(model.CountryCode))
            {
                where += $@" AND ""CountryCode"" = '{model.CountryCode}'";
            }

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

            if (model.IsSMSAvailable != null)
            {
                if ((bool)model.IsSMSAvailable)
                {
                    where += $@" AND (""SMSUrl"" = '') IS NOT FALSE";
                }
                else
                {
                    where += $@" AND (""SMSUrl"" = '') IS NOT TRUE";
                }
            }

            var query = $@"SELECT COUNT(*) OVER () AS ""TotalItems"", ""CountryId"", ""CountryName"", ""CountryCode"", ""ISOCode"", ""PriceSymbol"", ""Active"", ""SMSUrl"", ""SMSFrom"", ""SMSAuthorization"", ""SMSUsername"", ""CreatedDate"", ""ModifiedDate"" FROM ""Country"" {where} Order by ""CountryId"" DESC";

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

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

        /// <inheritdoc />
        public Task<CountryModel> FindAsync(int countryId)
        {
            var query = $@"SELECT * FROM ""Country"" cat WHERE ""CountryId"" = '{countryId}' AND ""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<CountryModel>(query);
        }

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

            var country = new Country
            {
                Active = true,
                CountryName = model.CountryName.Trim(),
                CountryCode = model.CountryCode,
                ISOCode = model.ISOCode,
                SMSUrl = model.SMSUrl,
                SMSAuthorization = model.SMSAuthorization,
                SMSFrom = model.SMSFrom,
                SMSUsername = model.SMSUsername,
                Currency = model.Currency,
                CurrencySymbol = model.CurrencySymbol,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow
            };

            return await this.unitOfWork.Countries.InsertAsync(country);
        }

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

            var country = await this.unitOfWork.Countries.FindAsync(m => m.CountryId == model.CountryId);
            country.CountryName = model.CountryName.Trim();
            country.CountryCode = model.CountryCode;
            country.ISOCode = model.ISOCode;
            country.SMSUrl = model.SMSUrl;
            country.SMSAuthorization = model.SMSAuthorization;
            country.SMSUsername = model.SMSUsername;
            country.CurrencySymbol = model.CurrencySymbol;
            country.Currency = model.Currency;
            country.SMSFrom = model.SMSFrom;
            country.ModifiedBy = model.ModifiedBy;
            country.ModifiedDate = DateTime.UtcNow;

            return await this.unitOfWork.Countries.UpdateAsync(country);
        }

        /// <inheritdoc />
        public Task<int> DeleteAsync(int countryId)
        {
            var query = $@"DELETE FROM ""Country"" WHERE ""CountryId""= {countryId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<int> ModifyStatusAsync(int countryId, int modifiedBy, bool status)
        {
            var query = $@"UPDATE ""Country"" SET ""Active"" = {status}, ""ModifiedBy"" = {modifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""CountryId""= {countryId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }
    }
}