namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Entities;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Shared.EntityModels;
    using Shared.UserModels.Filters;
    using Shared.UserModels.Pharmacy;

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

        /// <inheritdoc cref="IDepartmentService" />
        public DepartmentService(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc />
        public Task<IEnumerable<DepartmentModel>> FetchAsync(DepartmentFilterModel model)
        {
            var where = " WHERE 1 = 1 ";

            if (model.CreatedBy != 0)
            {
                where += $@"and D.""CreatedBy"" = '{model.CreatedBy}'";
            }           
            if (model.FromDate != null)
            {
                where += $@" and  D.""CreatedDate""::date >= '{model.FromDate}' ";
            }
            if (model.ToDate != null)
            {
                where += $@" and  D.""CreatedDate""::date <= '{model.ToDate}' ";
            }

            if (model.LocationIds != 0)
            {
                where += $@" and L.""LocationId""={model.LocationIds} ";
            }
            if (model.DepartmentId != null)
            {
                where += $@" and D.""DepartmentId""={model.DepartmentId} ";
            }
            if (!string.IsNullOrEmpty(model.DepartmentName))
            {
                where += $@" AND TRIM(UPPER(""DepartmentName"")) = '{model.DepartmentName.Trim().ToUpper()}'";
            }
            if (model.Active)
            {
                where += $@" and ""Active"" is true";
            }

            var query = $@"select 
                    Count(*) OVER() AS ""TotalItems"",D.*,
                    string_agg(l.""Name"", ', ') as ""LocationNames"",string_agg(l.""LocationId""::text, ', ') as ""LocationIds""
    
                    from ""Department"" D
                    left join ""LocationDepartmentMap"" LM ON LM.""DepartmentId"" = D.""DepartmentId""
                    left join ""Location"" L ON L.""LocationId"" = LM.""LocationId""
                 {where}
                    group by  D.""DepartmentId"" order by D.""CreatedDate"" desc	 ";

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

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

        }

        /// <inheritdoc />
        public async Task<int> AddAsync(DepartmentModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                try
                {
                    var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""DepartmentId"") FROM ""Department"" WHERE TRIM(UPPER(""DepartmentName"")) = '{model.DepartmentName.ToUpper().Trim()}'");
                    //var query = $@"select COUNT(d.""DepartmentId"") FROM ""Department"" d join ""LocationDepartmentMap"" ldm on d.""DepartmentId"" = ldm.""DepartmentId"" WHERE TRIM(UPPER(""DepartmentName"")) = '{model.DepartmentName.ToUpper().Trim()}' AND ldm.""LocationId"" IN( {model.LocationIds} )";
                    //var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(query);
                    if (checkIf > 0)
                    {
                        return -1;
                    }

                    var department = new Department
                    {

                        DepartmentName = model.DepartmentName,
                        DeptType=model.DeptType,
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        Active = true,

                    };

                    department.DepartmentId = await this.unitOfWork.Departments.InsertAsync(department, transaction);

                    if (department.DepartmentId == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }

                    if (model.LocationIds != null)
                    {
                        var ids = model.LocationIds.Split(',');
                        foreach (var locationId in ids)
                        {
                            var location = new LocationDepartmentMap
                            {
                                DepartmentId = department.DepartmentId,
                                LocationId = Convert.ToInt32(locationId)
                            };
                            var locationInsertId = await this.unitOfWork.LocationDepartmentMap.InsertAsync(location, transaction);
                            if (locationInsertId == 0)
                            {
                                transaction.Rollback();
                                return 0;
                            }
                        }
                    }
                    transaction.Commit();
                    return department.DepartmentId;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message.ToString());
                    return 0;
                }
            }
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(DepartmentModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""DepartmentId"") FROM ""Department"" WHERE TRIM(UPPER(""DepartmentName"")) = '{model.DepartmentName.ToUpper().Trim()}' AND ""DepartmentId"" <> {model.DepartmentId}");
                if (checkIf > 0)
                {
                    return -1;
                }

                var department = await this.unitOfWork.Departments.FindAsync(m => m.DepartmentId == model.DepartmentId);
                department.DepartmentName = model.DepartmentName;
                department.DeptType = model.DeptType;
                department.Active = true;
                department.ModifiedBy = model.ModifiedBy;
                department.ModifiedDate = DateTime.Now;

                var updated = await this.unitOfWork.Departments.UpdateAsync(department, transaction);
                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                var query = $@"DELETE from ""LocationDepartmentMap"" where ""DepartmentId""= {department.DepartmentId} ";
                var res = await this.unitOfWork.Current.QuerySingleOrDefaultAsync(query, transaction);
                if (res == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                if (model.LocationIds != null)
                {
                    var ids = model.LocationIds.Split(',');
                    foreach (var locationId in ids)
                    {

                        var location = new LocationDepartmentMap
                        {
                            DepartmentId = department.DepartmentId,
                            LocationId = Convert.ToInt32(locationId)
                        };
                        var locationInsertId = await this.unitOfWork.LocationDepartmentMap.InsertAsync(location, transaction);
                        if (locationInsertId == 0)
                        {
                            transaction.Rollback();
                            return 0;
                        }
                    }
                }
                transaction.Commit();
                return updated;
            }
        }

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

        public async Task<string> FindNameByDepartmentId(int departmentId)
        {

            var query = $@"SELECT ""DepartmentName"" FROM ""Department"" WHERE ""DepartmentId"" = {departmentId}";

            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);

            return response;
        }       
    }
}