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 Hims.Shared.UserModels.Common;
    using Hims.Shared.UserModels.DynamicDashboard;
    using Hims.Shared.UserModels.DynamicDashboard.Config;
    using Shared.EntityModels;

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

        /// <inheritdoc cref="IDynamicDashboardService" />
        public DynamicDashboardService(IUnitOfWork unitOfWork)
        {
            this.unitOfWork = unitOfWork;
        }

        /// <inheritdoc />
        public async Task<IEnumerable<DashboardConfigModel>> FetchAsync(FetchFilterModel model)
        {
            try
            {
                var checkQuery = $@"SELECT COUNT(""DashboardConfigId"") FROM ""DashboardConfig"" c 
                                    JOIN ""DashboardConfigMaster"" m on m.""DashboardConfigMasterId"" = c.""DashboardConfigMasterId"" 
                                    WHERE m.""AccountId"" = {model.AccountId} ";

                var count = model.AccountId > 0
                    ? await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkQuery)
                    : 0;

                var where = count > 0
                    ? $@" mm.""AccountId"" = {model.AccountId ?? 0} "
                    : $@" mm.""RoleId"" = {model.RoleId ?? 0} ";

                var query = $@"SELECT
	                            d.""DashboardConfigId"",
	                            mm.""DashboardConfigMasterId"",
	                            d.""DashboardWidgetId"",
	                            dw.""DashboardWidgetTypeId"",
	                            dw.""Icon"",
	                            dw.""DashboardWidgetCountTypeId"",
	                            dw.""Name"" ""WidgetName"",
	                            dwc.""Name"" ""CountTypeName"",
	                            dw.""StoredProcedureName"",
                                d.""RowNumber"",
								d.""Size"",
								d.""SequenceNumber"",
								d.""CreatedBy"",
	                            a.""FullName"" ""CreatedByName"",
	                            m.""FullName"" ""ModifiedByName"",
	                            d.""CreatedDate"",
	                            d.""ModifiedDate"",
	                            d.""DefaultValues""
                            FROM
	                            ""DashboardConfigMaster"" mm
								JOIN ""DashboardConfig"" d on d.""DashboardConfigMasterId"" = mm.""DashboardConfigMasterId""
	                            JOIN ""DashboardWidget"" dw on  dw.""DashboardWidgetId"" = d.""DashboardWidgetId""
	                            JOIN ""DashboardWidgetCountType"" dwc on  dwc.""DashboardWidgetCountTypeId"" = dw.""DashboardWidgetCountTypeId""
	                            JOIN ""Account"" a on a.""AccountId"" = d.""CreatedBy""
								LEFT JOIN ""Account"" m on m.""AccountId"" = d.""ModifiedBy""
								where {where}
                                order by d.""DashboardConfigId"" desc";
                var result = await this.unitOfWork.Current.QueryAsync<DashboardConfigModel>(query);

                if (result.Any() && count == 0)
                {
                    result.First().IsRoleDashboard = true;
                }

                return result;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <inheritdoc />
        public async Task<GenericResponse> InsertAsync(InsertModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();

            var configMaster = new DashboardConfigMaster
            {
                RoleId = model.RoleId,
                AccountId = model.AccountId
            };

            var existingMaster = await this.unitOfWork.DashboardConfigMaster.FindAsync(x => x.RoleId == model.RoleId && x.AccountId == model.AccountId);
            if (existingMaster != null && model.DashboardConfigMasterId == null)
            {
                model.DashboardConfigMasterId = existingMaster.DashboardConfigMasterId;
            };

            var configMasterId = model.DashboardConfigMasterId != null
                ? model.DashboardConfigMasterId
                : await this.unitOfWork.DashboardConfigMaster.InsertAsync(configMaster, transaction);

            var configs = model.Rows.Select(x => new DashboardConfig
            {
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                DashboardWidgetId = x.DashboardWidgetId,
                RowNumber = x.RowNumber,
                Size = x.Size,
                SequenceNumber = x.SequenceNumber,
                DashboardConfigMasterId = configMasterId ?? 0,
                DefaultValues = x.DefaultValues
            });

            var result = 0;
            foreach (var config in configs)
            {
                var existingCount = await this.unitOfWork.DashboardConfig.CountAsync(x => x.DashboardWidgetId == config.DashboardWidgetId && x.DashboardConfigMasterId == config.DashboardConfigMasterId);
                if (existingCount <= 0)
                {
                    result = await this.unitOfWork.DashboardConfig.InsertAsync(config, transaction);
                    if (result <= 0)
                    {
                        transaction.Rollback();
                        result = -1;
                        break;
                    }
                }
            }

            if (result > 0)
            {
                transaction.Commit();
            }

            return new GenericResponse
            {
                Status = result >= 0
                ? GenericStatus.Success
                : GenericStatus.Error
            };
        }

        //public async Task<int> UpdateAsync(DashboardConfigModel model)
        //{
        //    var transaction = this.unitOfWork.BeginTransaction();
        //    var query = $@"SELECT ""DashboardConfigId"" from ""DashboardConfig"" WHERE ""DashboardConfigId"" = {model.DashboardConfigId}";
        //    var isExists = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(query, transaction);

        //    var result = 0;
        //    if (isExists > 0)
        //    {
        //        var config = await this.unitOfWork.DashboardConfig.FindAsync(x => x.DashboardConfigId == model.DashboardConfigId, transaction);

        //        config.ModifiedBy = model.ModifiedBy;
        //        config.ModifiedDate = DateTime.Now;
        //        config.DashboardWidgetId = model.DashboardWidgetId;
        //        config.RowNumber = model.RowNumber;
        //        config.Size = model.Size;
        //        config.SequenceNumber = model.SequenceNumber;

        //        result = await this.unitOfWork.DashboardConfig.UpdateAsync(config, transaction);
        //    }

        //    if (result <= 0)
        //    {
        //        transaction.Rollback();
        //        return -1;
        //    }

        //    transaction.Commit();
        //    return result;

        //}

        /// <inheritdoc />
        public async Task<bool> DeleteAsync(int id)
        {
            return await this.unitOfWork.DashboardConfig.DeleteAsync(x => x.DashboardConfigId == id);
        }
    }
}