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

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

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

        /// <inheritdoc />
        public Task<IEnumerable<LabOrderModel>> FetchAsync(LabOrderFilterModel model)
        {
            var where = " WHERE 1 = 1 ";
            if (!string.IsNullOrEmpty(model.Name))
            {
                where += $@" AND ""Name"" ILIKE '%{model.Name}%'";
            }

            var query = $@"SELECT COUNT(*) OVER () AS ""TotalItems"", ""LabOrderId"", ""Name"", ""Type"",
            ""CreatedDate"", ""CreatedBy"" FROM ""LabOrder"" {where} Order by ""LabOrderId"" DESC";

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

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

        /// <inheritdoc />
        public async Task<int> AddAsync(LabOrderModel model)
        {
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""LabOrderId"") FROM ""LabOrder"" WHERE ""Name"" = '{model.Name.Trim()}' AND ""LabOrderId"" <> {model.LabOrderId}");
            if (checkIf > 0)
            {
                return -1;
            }

            var labOrder = new LabOrder
                               {
                                   Name = model.Name,
                                   Type = model.Type,
                                   CreatedBy = model.CreatedBy,
                                   CreatedDate = DateTime.UtcNow
                               };

            return await this.unitOfWork.LabOrder.InsertAsync(labOrder);
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(LabOrderModel model)
        {
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""LabOrderId"") FROM ""LabOrder"" WHERE ""Name"" = '{model.Name?.Trim()}' AND ""LabOrderId"" <> {model.LabOrderId}");
            if (checkIf > 0)
            {
                return -1;
            }

            var labOrder = await this.unitOfWork.LabOrder.FindAsync(m => m.LabOrderId == model.LabOrderId);
            labOrder.LabOrderId = model.LabOrderId;
            labOrder.Type = model.Type?.Trim();
            labOrder.Name = model.Name?.Trim();
            labOrder.ModifiedBy = model.ModifiedBy;
            labOrder.ModifiedDate = DateTime.UtcNow;

            return await this.unitOfWork.LabOrder.UpdateAsync(labOrder);
        }

        /// <inheritdoc />
        public async Task<int> DeleteAsync(int labOrderId)
        {
            var query = $@"DELETE FROM ""LabOrderValue"" WHERE ""LabOrderId""= {labOrderId}";
            await this.unitOfWork.Current.ExecuteAsync(query);
            
            query = $@"DELETE FROM ""LabOrder"" WHERE ""LabOrderId""= {labOrderId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }
    }
}