public FinalBillingModule(IRepository<FinalBilling> finalBillingDBRepository, IRepository<UserMeta> userMetaRepository, IRepository<AccountMeta> accountMetaRepository,
                                    ICacheProvider<FinalBilling> finalBillingCacheProvider)
        {
            this.RequiresAnyClaim(new[] { RoleType.Admin.ToString(), RoleType.ProductManager.ToString(), RoleType.Support.ToString() });

            _finalBillingDBRepository = finalBillingDBRepository;
            finalBillingRepository = finalBillingCacheProvider.CacheClient.GetAll();

            var endDateFilter = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 25);
            var startDateFilter = new DateTime(DateTime.UtcNow.Year, (DateTime.UtcNow.Month - 1), 26);

            Before += async (ctx, ct) =>
            {
                this.Info(() => "Before Hook - FinalBilling");
                await CheckCache(ct);
                return null;
            };

            After += async (ctx, ct) => this.Info(() => "After Hook - FinalBilling");

            Get["/FinalBilling/"] = _ =>
            {
                var finalBillingStartDateFilter = Request.Query["startDate"];
                var finalBillingEndDateFilter = Request.Query["endDate"];

                if (!finalBillingStartDateFilter.HasValue && !finalBillingEndDateFilter.HasValue) return Negotiate.WithView("Index");

                if (finalBillingStartDateFilter.HasValue) startDateFilter = finalBillingStartDateFilter;
                if (finalBillingEndDateFilter.HasValue) endDateFilter = finalBillingEndDateFilter;

                endDateFilter = endDateFilter.AddHours(23).AddMinutes(59).AddSeconds(59);

                var customerClientList = new List<FinalBillingDto>();

                foreach (var transaction in finalBillingRepository)
                {
                    var customerClientIndex = customerClientList.FindIndex(x => x.Id == transaction.CustomerId || x.Id == transaction.ClientId);
                    if (customerClientIndex > 0) continue;

                    var customerClient = new FinalBillingDto();
                    var userList = new List<User>();

                    var customerTransactions = finalBillingRepository.Where(x => x.CustomerId == transaction.CustomerId
                                                                            && (x.Created >= startDateFilter && x.Created <= endDateFilter)).DistinctBy(x => x.UserTransaction.TransactionId);

                    var customerPackages = customerTransactions.Where(x => x.CustomerId == transaction.CustomerId)
                                                        .Select(x => x.Package.PackageId).Distinct().Count();

                    var customerUsers = customerTransactions.Where(x => x.CustomerId == transaction.CustomerId).DistinctBy(x => x.User.UserId).Count();


                    var clientTransactions = finalBillingRepository.Where(x => x.ClientId == transaction.ClientId).DistinctBy(x => x.UserTransaction.TransactionId);

                    var clientPackagesTotal = clientTransactions.Where(x => x.ClientId == transaction.ClientId)
                                                        .Select(x => x.Package.PackageId).Distinct().Count();

                    var clientUsers = customerTransactions.Where(x => x.ClientId == transaction.ClientId).DistinctBy(x => x.User.UserId).Count();

                    // Customer
                    if (transaction.ClientId == new Guid())
                    {
                        customerClient = new FinalBillingDto
                        {
                            Id = transaction.CustomerId,
                            CustomerName = transaction.CustomerName,
                            Transactions = customerTransactions.Count(),
                            Products = customerPackages,
                            AccountMeta = accountMetaRepository.FirstOrDefault(x => x.AccountNumber == transaction.AccountNumber)
                        };

                        customerClient.Users = customerUsers;
                    }

                    // Client
                    if (transaction.CustomerId == new Guid())
                    {
                        customerClient = new FinalBillingDto
                        {
                            Id = transaction.ClientId,
                            CustomerName = transaction.ClientName,
                            Transactions = clientTransactions.Count(),
                            Products = clientPackagesTotal,
                            AccountMeta = accountMetaRepository.FirstOrDefault(x => x.AccountNumber == transaction.AccountNumber)
                        };

                        customerClient.Users = clientUsers;
                    }

                    if (customerClientIndex < 0 && customerClient.Transactions > 0) customerClientList.Add(customerClient);
                }

                return Negotiate
                    .WithView("Index")
                    .WithMediaRangeModel(MediaRange.FromString("application/json"), new { data = customerClientList });
            };


            Get["/FinalBilling/CustomerClient/{searchId}/Users"] = param =>
            {
                var stageBillingStartDateFilter = Request.Query["startDate"];
                var stageBillingEndDateFilter = Request.Query["endDate"];

                if (stageBillingStartDateFilter.HasValue) startDateFilter = stageBillingStartDateFilter;
                if (stageBillingEndDateFilter.HasValue) endDateFilter = stageBillingEndDateFilter;

                endDateFilter = endDateFilter.AddHours(23).AddMinutes(59).AddSeconds(59);

                var searchId = new Guid(param.searchId);
                var customerUsersDetailList = new List<UserDto>();

                var finalBillingRepo = finalBillingRepository.Where(x => (x.CustomerId == searchId || x.ClientId == searchId)
                                                                    && (x.Created >= startDateFilter && x.Created <= endDateFilter)).DistinctBy(x => x.UserTransaction.TransactionId);

                foreach (var transaction in finalBillingRepo)
                {
                    var userTransactionsList = new List<TransactionDto>();

                    var userMeta = userMetaRepository.FirstOrDefault(x => x.Id == transaction.User.UserId) ?? new UserMeta
                    {
                        Id = transaction.User.UserId,
                        Username = transaction.User.Username
                    };

                    // Filter repo for user transaction;
                    var userTransactions = finalBillingRepo.Where(x => x.User.UserId == transaction.User.UserId)
                                            .Select(x =>
                                            new TransactionDto
                                            {
                                                TransactionId = x.UserTransaction.TransactionId,
                                                RequestId = x.UserTransaction.RequestId,
                                                IsBillable = x.UserTransaction.IsBillable
                                            }).Distinct();

                    foreach (var userTransaction in userTransactions)
                    {
                        var userTransIndex = userTransactionsList.FindIndex(x => x.TransactionId == userTransaction.TransactionId);
                        if (userTransIndex < 0) userTransactionsList.Add(userTransaction);
                    }

                    var user = Mapper.Map<FinalBilling, UserDto>(transaction);
                    Mapper.Map(userMeta, user);
                    user.Transactions = userTransactionsList;

                    var userIndex = customerUsersDetailList.FindIndex(x => x.UserId == user.UserId);
                    if (userIndex < 0) customerUsersDetailList.Add(user);
                }

                return Response.AsJson(new { data = customerUsersDetailList });
            };


            Get["/FinalBilling/CustomerClient/{searchId}/Packages"] = param =>
            {
                var stageBillingStartDateFilter = Request.Query["startDate"];
                var stageBillingEndDateFilter = Request.Query["endDate"];

                if (stageBillingStartDateFilter.HasValue) startDateFilter = stageBillingStartDateFilter;
                if (stageBillingEndDateFilter.HasValue) endDateFilter = stageBillingEndDateFilter;

                endDateFilter = endDateFilter.AddHours(23).AddMinutes(59).AddSeconds(59);

                var searchId = new Guid(param.searchId);
                var customerPackagesDetailList = new List<PackageDto>();

                var finalBillingRepo = finalBillingRepository.Where(x => (x.CustomerId == searchId || x.ClientId == searchId)
                                                                    && (x.Created >= startDateFilter && x.Created <= endDateFilter)).DistinctBy(x => x.UserTransaction.TransactionId);

                foreach (var transaction in finalBillingRepo)
                {
                    var packageTransactions = finalBillingRepo.Where(x => x.Package.PackageId == transaction.Package.PackageId).Distinct();

                    var package = Mapper.Map<Package, PackageDto>(transaction.Package);
                    package.PackageTransactions = packageTransactions.Count();
                    package.Created = transaction.Created;

                    var packageIndex = customerPackagesDetailList.FindIndex(x => x.PackageId == package.PackageId);
                    if (packageIndex < 0) customerPackagesDetailList.Add(package);

                    if (packageIndex >= 0)
                    {
                        if (customerPackagesDetailList[packageIndex].Created < package.Created)
                        {
                            customerPackagesDetailList[packageIndex] = package;
                        }
                    }
                }

                return Response.AsJson(new { data = customerPackagesDetailList });
            };

        }
        private Profile GetProfile(string username, bool isAnonymous, IRepository<Profile> profiles)
        {
            var profile = profiles
                .FirstOrDefault(p =>
                          p.User.UserName == username
                          && p.ApplicationName == ApplicationName
                          && p.IsAnonymous == isAnonymous);

            if (profile == null)
            {
                var membershipUser = UnitOfWork.Current.CreateRepository<User>()
                    .FirstOrDefault(p => p.UserName == username
                    && p.ApplicationName == ApplicationName);

                if (membershipUser == null)
                    throw new ProviderException("Profile cannot be created. There is no membership user");

                profile = new Profile();
                profile.IsAnonymous = isAnonymous;
                profile.LastUpdatedDate = System.DateTime.Now;
                profile.LastActivityDate = System.DateTime.Now;
                profile.ApplicationName = this.ApplicationName;
                profile.UserId = membershipUser.Id;

                profiles.Insert(profile);
            }
            return profile;
        }
        public PreBillingModule(IRepository<PreBilling> preBillingDBRepository, 
                                IRepository<AccountMeta> accountMetaRepository, IRepository<UserMeta> userMetaRepository, ICacheProvider<PreBilling> preBillingCacheProvider,
                                IReportApiClient reportApiClient)
        {
            this.RequiresAnyClaim(new[] { RoleType.Admin.ToString(), RoleType.ProductManager.ToString(), RoleType.Support.ToString() });

            _preBillingDBRepository = preBillingDBRepository;
            _preBillingRepository = preBillingCacheProvider.CacheClient.GetAll();

            var endDateFilter = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 25);
            var startDateFilter = new DateTime(DateTime.UtcNow.Year, (DateTime.UtcNow.Month - 1), 26);

            Before += async (ctx, ct) =>
            {
                this.Info(() => "Before Hook - PreBilling");
                await CheckCache(ct);
                return null;
            };

            After += async (ctx, ct) => this.Info(() => "After Hook - PreBilling");

            Get["/PreBilling/"] = _ =>
            {
                var preBillStartDateFilter = Request.Query["startDate"];
                var preBillEndDateFilter = Request.Query["endDate"];

                if (!preBillStartDateFilter.HasValue && !preBillEndDateFilter.HasValue) return Negotiate.WithView("Index");

                if (preBillStartDateFilter.HasValue) startDateFilter = preBillStartDateFilter;
                if (preBillEndDateFilter.HasValue) endDateFilter = preBillEndDateFilter;

                endDateFilter = endDateFilter.AddHours(23).AddMinutes(59).AddSeconds(59);

                var customerClientList = new List<PreBillingDto>();

                foreach (var transaction in _preBillingRepository)
                {
                    var customerClientIndex = customerClientList.FindIndex(x => x.Id == transaction.CustomerId || x.Id == transaction.ClientId);
                    if (customerClientIndex > 0) continue;

                    var customerClient = new PreBillingDto();
                    

                    var customerTransactions = _preBillingRepository.Where(x => x.CustomerId == transaction.CustomerId
                                                                            && (x.Created >= startDateFilter && x.Created <= endDateFilter))
                                                                            .DistinctBy(x => x.UserTransaction.TransactionId);

                    var customerPackages = customerTransactions.Where(x => x.CustomerId == transaction.CustomerId)
                                                        .Select(x => x.Package.PackageId).Distinct().Count();

                    var customerUsers = customerTransactions.Where(x => x.CustomerId == transaction.CustomerId).DistinctBy(x => x.User.UserId).Count();


                    var clientTransactions = _preBillingRepository.Where(x => x.ClientId == transaction.ClientId
                                                                            && (x.Created >= startDateFilter && x.Created <= endDateFilter))
                                                                            .DistinctBy(x => x.UserTransaction.TransactionId);

                    var clientPackagesTotal = clientTransactions.Where(x => x.ClientId == transaction.ClientId)
                                                        .Select(x => x.Package.PackageId).Distinct().Count();

                    var clientUsers = customerTransactions.Where(x => x.ClientId == transaction.ClientId).DistinctBy(x => x.User.UserId).Count();

                    if (customerTransactions.Count() < 0 && clientTransactions.Count() < 0) continue;

                    // Customer
                    if (transaction.ClientId == new Guid())
                    {
                        customerClient = new PreBillingDto
                        {
                            Id = transaction.CustomerId,
                            CustomerName = transaction.CustomerName,
                            Transactions = customerTransactions.Count(),
                            Products = customerPackages,
                            AccountMeta = accountMetaRepository.FirstOrDefault(x => x.AccountNumber == transaction.AccountNumber),
                        };

                        customerClient.Users = customerUsers;
                    }

                    // Client
                    if (transaction.CustomerId == new Guid())
                    {
                        customerClient = new PreBillingDto
                        {
                            Id = transaction.ClientId,
                            CustomerName = transaction.ClientName,
                            Transactions = clientTransactions.Count(),
                            Products = clientPackagesTotal,
                            AccountMeta = accountMetaRepository.FirstOrDefault(x => x.AccountNumber == transaction.AccountNumber)
                        };

                        customerClient.Users = clientUsers;
                    }

                   if ((transaction.ClientId == new Guid()) && (transaction.CustomerId == new Guid())) continue;

                   if (customerClientIndex < 0 && customerClient.Transactions > 0) customerClientList.Add(customerClient);
                }

                return Negotiate
                    .WithView("Index")
                    .WithMediaRangeModel(MediaRange.FromString("application/json"), new { data = customerClientList });
            };


            Get["/PreBilling/CustomerClient/{searchId}/Users"] = param =>
            {
                var preBillStartDateFilter = Request.Query["startDate"];
                var preBillEndDateFilter = Request.Query["endDate"];

                if (preBillStartDateFilter.HasValue) startDateFilter = preBillStartDateFilter;
                if (preBillEndDateFilter.HasValue) endDateFilter = preBillEndDateFilter;

                endDateFilter = endDateFilter.AddHours(23).AddMinutes(59).AddSeconds(59);

                var searchId = new Guid(param.searchId);
                var customerUsersDetailList = new List<UserDto>();

                var preBillingRepo = _preBillingRepository.Where(x => (x.CustomerId == searchId || x.ClientId == searchId)
                                                                    && (x.Created >= startDateFilter && x.Created <= endDateFilter)).DistinctBy(x => x.UserTransaction.TransactionId);

                foreach (var transaction in preBillingRepo)
                {
                    var userTransactionsList = new List<TransactionDto>();

                    var userMeta = userMetaRepository.FirstOrDefault(x => x.Id == transaction.User.UserId) ?? new UserMeta
                    {
                        Id = transaction.User.UserId,
                        Username = transaction.User.Username
                    };

                    // Filter repo for user transaction;
                    var userTransactions = preBillingRepo.Where(x => x.User.UserId == transaction.User.UserId)
                                            .Select(x =>
                                            new TransactionDto
                                            {
                                                TransactionId = x.UserTransaction.TransactionId,
                                                RequestId = x.UserTransaction.RequestId,
                                                IsBillable = x.UserTransaction.IsBillable
                                            }).Distinct();

                    foreach (var userTransaction in userTransactions)
                    {
                        var userTransIndex = userTransactionsList.FindIndex(x => x.TransactionId == userTransaction.TransactionId);
                        if (userTransIndex < 0) userTransactionsList.Add(userTransaction);
                    }

                    var user = Mapper.Map<PreBilling, UserDto>(transaction);
                    Mapper.Map(userMeta, user);
                    user.Transactions = userTransactionsList;

                    var userIndex = customerUsersDetailList.FindIndex(x => x.UserId == user.UserId);
                    if (userIndex < 0) customerUsersDetailList.Add(user);
                }

                return Response.AsJson(new { data = customerUsersDetailList });
            };


            Get["/PreBilling/CustomerClient/{searchId}/Packages"] = param =>
            {
                var preBillStartDateFilter = Request.Query["startDate"];
                var preBillEndDateFilter = Request.Query["endDate"];

                if (preBillStartDateFilter.HasValue) startDateFilter = preBillStartDateFilter;
                if (preBillEndDateFilter.HasValue) endDateFilter = preBillEndDateFilter;

                endDateFilter = endDateFilter.AddHours(23).AddMinutes(59).AddSeconds(59);

                var searchId = new Guid(param.searchId);
                var customerPackagesDetailList = new List<PackageDto>();

                var preBillingRepo = _preBillingRepository.Where(x => (x.CustomerId == searchId || x.ClientId == searchId)
                                                                    && (x.Created >= startDateFilter && x.Created <= endDateFilter)).DistinctBy(x => x.UserTransaction.TransactionId);

                foreach (var transaction in preBillingRepo)
                {
                    var packageTransactions = preBillingRepo.Where(x => x.Package.PackageId == transaction.Package.PackageId).Distinct();

                    var package = Mapper.Map<Package, PackageDto>(transaction.Package);
                    package.PackageTransactions = packageTransactions.Count();
                    package.Created = transaction.Created;

                    var packageIndex = customerPackagesDetailList.FindIndex(x => x.PackageId == package.PackageId);

                    if (packageIndex < 0) customerPackagesDetailList.Add(package);

                    if (packageIndex >= 0)
                    {
                        if (customerPackagesDetailList[packageIndex].Created < package.Created)
                        {
                            customerPackagesDetailList[packageIndex] = package;
                        }
                    }
                }

                return Response.AsJson(new { data = customerPackagesDetailList });
            };

            Get["/PreBillingDump"] = _ =>
            {
                var preBillStartDateFilter = Request.Query["startDate"];
                var preBillEndDateFilter = Request.Query["endDate"];

                if (preBillStartDateFilter.HasValue) startDateFilter = preBillStartDateFilter;
                if (preBillEndDateFilter.HasValue) endDateFilter = preBillEndDateFilter;

                endDateFilter = endDateFilter.AddHours(23).AddMinutes(59).AddSeconds(59);

                var preBilling = _preBillingRepository.Where(x => x.Created >= startDateFilter && x.Created <= endDateFilter);

                var report = new ReportDto
                {
                    Template = new ReportTemplate { ShortId = "418Ky2Cj" },
                    Data = new ReportData
                    {
                        PreBillingData = Mapper.Map<IEnumerable<PreBilling>, IEnumerable<PreBillingRecord>>(preBilling)
                    }
                };

                var token = Context.Request.Headers.Authorization.Split(' ')[1];
                reportApiClient.Post(token, "/PreBillingReportDownload?startDate=" + startDateFilter + "&endDate="+ endDateFilter, null, report, null);


                var file = new FileStream(@"D:\LSA Reports\PreBilling " + startDateFilter.ToString("MMMM dd yyyy") + " - " + endDateFilter.ToString("MMMM dd yyyy") + ".xlsx", FileMode.Open);
                string fileName = "PreBilling_" + startDateFilter.ToString("MMMM-dd-yyyy") + "_" + endDateFilter.ToString("MMMM-dd-yyyy") + ".xlsx";

                var response = new StreamResponse(() => file, MimeTypes.GetMimeType(fileName));

                response.WithCookie("fileDownload", "true", DateTime.UtcNow.AddSeconds(10), "", "/");

                return response.AsAttachment(fileName);
            };

        }