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 CouponServices : ICouponService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <inheritdoc cref="ICouponService" />
        public CouponServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

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

            if (!string.IsNullOrEmpty(model.FromDate) && !string.IsNullOrEmpty(model.ToDate))
            {
                where += $@" AND ""ValidFrom""::DATE >= '{model.FromDate}'::DATE";
                where += $@" AND ""ValidTo""::DATE <= '{model.ToDate}'::DATE";
            }

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

            var query = $@"SELECT COUNT(*) OVER () AS ""TotalItems"", * FROM ""Coupon"" {where} Order by ""CouponId"" DESC";

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

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

        /// <inheritdoc />
        public Task<IEnumerable<CouponModel>> FetchEligibleCouponsAsync(CouponFilterModel model)
        {
            //var where = " WHERE 1 = 1 ";
            //where += $@" and CURRENT_DATE BETWEEN ""ValidFrom"" AND ""ValidTo"" AND ""Active"" IS TRUE";

            //if (!string.IsNullOrEmpty(model.CouponCode))
            //{
            //    where += $@" AND TRIM(UPPER(c.""CouponCode"")) = '{model.CouponCode.Trim().ToUpper()}'";
            //}

            //var query = $@"SELECT c.* FROM ""Coupon"" c {where} Order by c.""CouponId"" DESC";

            var query1 = $@" SELECT c.* FROM ""Coupon"" c WHERE CURRENT_DATE BETWEEN ""ValidFrom"" AND ""ValidTo"" AND ""Active"" IS TRUE";

            var query = $@"{query1} except ({query1} and '{model.ProviderId}' = any(string_to_array(""NotAllowedProviderIds"",','))union {query1} and '{model.PatientId}' = any(string_to_array(""NotAllowedPatientIds"",',')))";

            return this.unitOfWork.Current.QueryAsync<CouponModel>(query);
        }

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

                var coupon = new Coupon
                {
                    Active = true,
                    CouponCode = model.CouponCode.Trim(),
                    CouponType = model.CouponType,
                    CouponValue = model.CouponValue,
                    ValidFrom = model.ValidFrom,
                    ValidTo = model.ValidTo,
                    AllowedPerUser = model.AllowedPerUser,
                    NotAllowedProviderIds = model.NotAllowedProviderIds,
                    NotAllowedPatientIds = model.NotAllowedPatientIds,
                    AllowedForFirstAppointment = model.AllowedForFirstAppointment,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.UtcNow,
                    Description = model.Description
                };

                return await this.unitOfWork.Coupons.InsertAsync(coupon);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message.ToString());
            }

            return 0;
        }

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

            var coupon = await this.unitOfWork.Coupons.FindAsync(m => m.CouponId == model.CouponId);
            coupon.CouponCode = model.CouponCode.Trim();
            coupon.CouponType = model.CouponType;
            coupon.CouponValue = model.CouponValue;
            coupon.AllowedPerUser = model.AllowedPerUser;
            coupon.NotAllowedProviderIds = model.NotAllowedProviderIds;
            coupon.NotAllowedPatientIds = model.NotAllowedPatientIds;
            coupon.ValidFrom = model.ValidFrom;
            coupon.ValidTo = model.ValidTo;
            coupon.AllowedForFirstAppointment = model.AllowedForFirstAppointment;
            coupon.ModifiedBy = model.ModifiedBy;
            coupon.ModifiedDate = DateTime.UtcNow;
            coupon.Description = model.Description;

            return await this.unitOfWork.Coupons.UpdateAsync(coupon);
        }

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

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

        /// <inheritdoc />
        public Task<CouponModel> ApplyAsync(string couponCode)
        {
            var query = $@"SELECT * FROM ""Coupon"" where  ""CouponCode"" = '{couponCode}' and CURRENT_DATE BETWEEN ""ValidFrom"" AND ""ValidTo"" AND ""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<CouponModel>(query);
        }

        /// <inheritdoc />
        public Task<CouponModel> FetchActiveCoupon(string couponCode)
        {
            var query = $@"SELECT * FROM ""Coupon"" where UPPER(""CouponCode"") = '{couponCode.ToUpper()}' and CURRENT_DATE BETWEEN ""ValidFrom"" AND ""ValidTo"" AND ""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<CouponModel>(query);
        }

        /// <inheritdoc />
        public Task<IEnumerable<AppointmentModel>> FetchPatientAppointments(int patientId)
        {
            var query = $@"SELECT * FROM ""Appointment"" where ""PatientId"" = {patientId} and ""Status"" = 'B' and ""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryAsync<AppointmentModel>(query);
        }
    }
}