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

        /// <summary>
        /// Initializes a new instance of the <see cref="WalletServices"/> class.
        /// </summary>
        /// <param name="unitOfWork">
        /// The unit of work.
        /// </param>
        public WalletServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc />
        public Task<IEnumerable<WalletModel>> FetchAsync(WalletFilterModel model)
        {
            var query = $@"WITH CTS AS(SELECT ""PatientId"", ""WalletId"", COALESCE(""CreditedAmount"", 0) AS ""CreditedAmount"", COALESCE(""DebitedAmount"", 0) AS ""DebitedAmount"", ""CreditedFor"", ""CreatedDate"" FROM ""Wallet"" )
                        ,TOTAL AS (SELECT ""PatientId"",COALESCE(SUM(""CreditedAmount""),0) AS ""TotalCredits"",COALESCE(SUM(""DebitedAmount""),0) AS ""TotalDebits""
                        FROM ""Wallet"" GROUP By ""PatientId"")
                        SELECT a.*,b.""TotalCredits"",b.""TotalDebits"" FROM CTS a
                        JOIN TOTAL b ON a.""PatientId""=b.""PatientId"" 
                        WHERE a.""PatientId"" = {model.PatientId} ORDER BY ""WalletId"" DESC ";

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

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

        /// <inheritdoc />
        public Task<WalletModel> FindAsync(int patientId)
        {
            var query = $@"SELECT ""PatientId"",COALESCE(SUM(""CreditedAmount""),0) AS ""TotalCredits"",COALESCE(SUM(""DebitedAmount""),0) AS ""TotalDebits""
                        FROM ""Wallet"" WHERE ""PatientId"" = {patientId} GROUP By ""PatientId""";

            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<WalletModel>(query);
        }

        /// <inheritdoc />
        public Task AddAsync(WalletModel model)
        {
            var wallet = new Wallet
            {
                CreatedDate = DateTime.UtcNow,
                PatientId = model.PatientId,
                CreditedAmount = model.CreditedAmount,
                DebitedAmount = model.DebitedAmount,
                CreditedFor = model.CreditedFor
            };

            return this.unitOfWork.Wallet.InsertAsync(wallet);
        }
    }
}