using Microsoft.EntityFrameworkCore;
using NetworkResurrector.Api.Domain.Data.DbContexts;
using NetworkResurrector.Api.Domain.Entities.Security;
using NetworkResurrector.Api.Domain.Repositories;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace NetworkResurrector.Api.Domain.Data.Repositories
{
    public class SecurityRepository : ISecurityRepository
    {
        private readonly NetworkDbContext _dbContext;

        public SecurityRepository(NetworkDbContext dbContext)
        {
            _dbContext=dbContext;
        }

        private async Task BuildChildrenHierarchy(Permission permission)
        {
            var children = await _dbContext.PermissionHierarchies
                .Include(z => z.Child)
                .Where(z => z.ParentPermissionId == permission.PermissionId)
                .AsNoTracking()
                .ToArrayAsync();

            if (children == null || !children.Any())
                return;

            permission.Children = children;

            foreach (var element in permission.Children)
            {
                await BuildChildrenHierarchy(element.Child);
            }
        }

        private IEnumerable<string> GetPermissionCodes(IEnumerable<Permission> permissions)
        {
            var result = new List<string>();
            foreach (var permission in permissions)
            {
                result.Add(permission.PermissionCode);
                if (permission.Children != null && permission.Children.Count > 0)
                {
                    var children = permission.Children.Select(ch => ch.Child);
                    var childrenCodes = GetPermissionCodes(children);
                    result.AddRange(childrenCodes);
                }
            }
            return result.Distinct();
        }

        private async Task<IEnumerable<Permission>> GetUserPermissions(IEnumerable<int> roles)
        {
            var authorizations = await _dbContext.UserRoleAuthorizations
                .Include(z => z.Permission)
                .AsNoTracking()
                .Where(z => roles.Contains(z.UserRoleId) && z.Active)
                .ToArrayAsync();

            var permissions = authorizations.Select(z => z.Permission);
            foreach (var permission in permissions)
            {
                await BuildChildrenHierarchy(permission);
            }

            return permissions;
        }

        public async Task<IEnumerable<string>> GetUserPermissionCodes(IEnumerable<int> roles)
        {
            var permissions = await GetUserPermissions(roles);
            var codes = GetPermissionCodes(permissions);
            return codes;
        }
    }
}
