using Dapper;

using Hims.Domain.Entities;
using Hims.Domain.Repositories.UnitOfWork;
using Hims.Domain.Services;
using Hims.Shared.EntityModels;

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Hims.Infrastructure.Services
{
    public class EmployeeShiftServices : IEmployeeShiftService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        public EmployeeShiftServices(IUnitOfWork unitOfWork)
        {
            this.unitOfWork = unitOfWork;
        }

        public async Task<int> AddAsync(EmployeeShiftModel model)
        {
            var shift = await this.unitOfWork.EmployeeShifts.FindAsync(m => m.LocationId == model.LocationId && m.EmployeeShiftName == model.EmployeeShiftName && m.StartTime == TimeSpan.Parse(model.StartTime) && m.EndTime == TimeSpan.Parse(model.EndTime));
            if (shift != null)
            {
                return -1;
            }

            var employeeShift = new EmployeeShift
            {
                EmployeeShiftName = model.EmployeeShiftName,
                LocationId = model.LocationId,
                StartTime = TimeSpan.Parse(model.StartTime),
                EndTime = TimeSpan.Parse(model.EndTime),
                Note = model.Note,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow,
                Active = true
            };
            return await this.unitOfWork.EmployeeShifts.InsertAsync(employeeShift);
        }

        public async Task<int> UpdateAsync(EmployeeShiftModel model)
        {
            var shift = await this.unitOfWork.EmployeeShifts.FindAsync(m => m.LocationId == model.LocationId && m.EmployeeShiftName == model.EmployeeShiftName && m.StartTime == TimeSpan.Parse(model.StartTime) && m.EndTime == TimeSpan.Parse(model.EndTime) && m.EmployeeShiftId != model.EmployeeShiftId);
            if (shift != null)
            {
                return -1;
            }

            var employeeShift = await this.unitOfWork.EmployeeShifts.FindAsync(m => m.EmployeeShiftId == model.EmployeeShiftId);
            employeeShift.EmployeeShiftName = model.EmployeeShiftName;
            employeeShift.LocationId = model.LocationId;
            employeeShift.StartTime = TimeSpan.Parse(model.StartTime);
            employeeShift.EndTime = TimeSpan.Parse(model.EndTime);
            employeeShift.Note = model.Note;
            employeeShift.ModifiedBy = model.ModifiedBy;
            employeeShift.ModifiedDate = DateTime.UtcNow;

            return await this.unitOfWork.EmployeeShifts.UpdateAsync(employeeShift);
        }

        public async Task<int> ChangeStatusAsync(EmployeeShiftModel model)
        {
            var employeeShift = await this.unitOfWork.EmployeeShifts.FindAsync(m => m.EmployeeShiftId == model.EmployeeShiftId);
            
            employeeShift.Active = model.Active;
            employeeShift.ModifiedBy = model.ModifiedBy;
            employeeShift.ModifiedDate = DateTime.UtcNow;

            return await this.unitOfWork.EmployeeShifts.UpdateAsync(employeeShift);
        }

        public async Task<IEnumerable<EmployeeShiftModel>> FetchAsync(EmployeeShiftFilterModel model)
        {
            var where = $@" WHERE 1=1 ";

            var query = $@"SELECT COUNT(*) OVER() AS ""TotalItems"", A.* FROM (SELECT L.""Name"" AS ""LocationName"", ES.""EmployeeShiftName"",
						""Note"", ""EmployeeShiftId"", ES.""CreatedDate"", ES.""CreatedBy"", ES.""Active"", ES.""LocationId"",
						TO_CHAR(""StartTime"" ,'hh12:mi AM')::text ""StartTime"", 
						TO_CHAR(""EndTime"" ,'hh12:mi AM')::text ""EndTime"" 
                        FROM ""EmployeeShift"" ES
                        JOIN ""Location"" L ON L.""LocationId"" = ES.""LocationId"" {where} ) A ";

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

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