using CloudBuilder.Core.DatabaseAccessor.Entity;
using CloudBuilder.Core.Service;
using CloudBuilder.Security.Data;
using CloudBuilder.Security.Entity;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CloudBuilder.Security.Service.Authorization
{
    public class PermissionContext
    {
        private readonly IApplicationService service;

        public PermissionContext(IApplicationService service)
        {
            this.service = service;
        }

        public string[] GetAllGroups()
        {
            if (string.IsNullOrEmpty(service.UserId)) return null!;

            var userActors = service.GetRepository<IRepository<SecurityUserActorEntity>>().DetachedEntities.Where(x => x.UserName == service.UserId);

            var actorGroups = service.GetRepository<IRepository<SecurityActorGroupEntity>>().DetachedEntities.Where(x => userActors.Select(x => x.ActorName).Contains(x.ActorName));

            if (!actorGroups.Any())
            {
                return null!;
            }

            return actorGroups.Select(x => x.GroupName).ToArray();
        }

        public SecurityUserPermissionInfo GetUserPermissionInfo()
        {
            SecurityUserPermissionInfo info = new SecurityUserPermissionInfo();

            var userActors = service.GetRepository<IRepository<SecurityUserActorEntity>>().DetachedEntities.Where(x => x.UserName == service.UserId);

            var actorGroups = service.GetRepository<IRepository<SecurityActorGroupEntity>>().DetachedEntities.Where(x => userActors.Select(x => x.ActorName).Contains(x.ActorName));

            info.UserGroups = actorGroups.Select(x => x.GroupName).ToArray();

            info.Permissions = (
                from p in service.GetRepository<IRepository<SecurityGroupPermissionViewEntity>>().DetachedEntities.AsEnumerable()
                join g in actorGroups on p.GroupName equals g.GroupName
                select p
            ).ToArray();
            info.PermissionDependents =
                 (
                from p in service.GetRepository<IRepository<SecurityGroupPermissionDependentViewEntity>>().DetachedEntities.AsEnumerable()
                join g in actorGroups on p.GroupName equals g.GroupName
                select p
            ).ToArray(); 
            info.PermissionFunctionMaps =
                (
                    from m in service.GetRepository<IRepository<SecurityPermissionFunctionMapViewEntity>>().DetachedEntities.AsEnumerable()
                    join p in info.Permissions on m.PermissionName equals p.PermissionName
                    select m
                ).ToArray();
            return info;
        }

        public bool CanNone(string permission)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.Permissions?.Any(x => x.PermissionName == permission) == true;
        }

        public bool CanView(string permission)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.Permissions?.Any(x => x.PermissionName == permission && x.ViewIndc == YesNoPolicy.YES) == true;
        }

        public bool CanCreate(string permission)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.Permissions?.Any(x => x.PermissionName == permission && x.CreateIndc == YesNoPolicy.YES) == true;
        }

        public bool CanAmend(string permission)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.Permissions?.Any(x => x.PermissionName == permission && x.AmendIndc == YesNoPolicy.YES) == true;
        }

        public bool CanDelete(string permission)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.Permissions?.Any(x => x.PermissionName == permission && x.DeleteIndc == YesNoPolicy.YES) == true;
        }

        public bool CanNone(string permission, string dependent)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent) == true;
        }

        public bool CanView(string permission, string dependent)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent && x.ViewIndc == YesNoPolicy.YES) == true;
        }

        public bool CanCreate(string permission, string dependent)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent && x.CreateIndc == YesNoPolicy.YES) == true;
        }

        public bool CanAmend(string permission, string dependent)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent && x.AmendIndc == YesNoPolicy.YES) == true;
        }

        public bool CanDelete(string permission, string dependent)
        {
            if (string.IsNullOrEmpty(service.UserId)) return false;

            SecurityUserPermissionInfo permissionInfo = GetUserPermissionInfo();
            return permissionInfo.PermissionDependents?.Any(x => x.PermissionName == permission && x.DependentDetailName == dependent && x.DeleteIndc == YesNoPolicy.YES) == true;
        }

    }
}
