using System;
using System.Linq;

namespace InABox.Core
{
    /// <summary>
    /// Causes a property to update its editable status based on <see cref="SecurityDescriptor"/>. If the current user does not have the security token,
    /// then the property's visiblity is restricted to at most <see cref="Editable"/>.
    /// </summary>
    /// <remarks>
    /// <see cref="Editable"/> defaults to <see cref="Editable.Hidden"/>.
    /// </remarks>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
    public class SecurityAttribute : Attribute
    {
        public Type SecurityDescriptor { get; set; }

        public Editable Editable { get; set; } = Editable.Hidden;

        private SecurityAttribute() { }

        public SecurityAttribute(Type securityDescriptor)
        {
            if (!securityDescriptor.GetInterfaces().Contains(typeof(ISecurityDescriptor)))
                throw new Exception(securityDescriptor.EntityName() + " is not a valid security descriptor!");
            SecurityDescriptor = securityDescriptor;
        }

        public virtual SecurityAttribute Clone()
        {
            var result = new SecurityAttribute(SecurityDescriptor)
            {
                SecurityDescriptor = SecurityDescriptor,
                Editable = Editable
            };
            return result;
        }
    }

    public class CanViewAttribute : SecurityAttribute
    {
        public CanViewAttribute(Type TEntity): base(
            typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanView<>).MakeGenericType(TEntity)))
        {
        }
    }

    public class CanEditAttribute : SecurityAttribute
    {
        public CanEditAttribute(Type TEntity) : base(
            typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanEdit<>).MakeGenericType(TEntity)))
        {

        }
    }

    public class CanDeleteAttribute : SecurityAttribute
    {
        public CanDeleteAttribute(Type TEntity) : base(
            typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanDelete<>).MakeGenericType(TEntity)))
        {

        }
    }
}
