using System.Globalization;
using System.Linq;
using System.Reflection;

namespace InABox.Core
{
    public interface IAutoSecurityAction<TEntity>
    {
        string Prefix { get; }

        string Postfix { get; }

        bool Value { get; }
    }

    public class CanView<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "View";

        public string Postfix => "";

        public bool Value => true;
    }

    public class CanEdit<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "Edit";

        public string Postfix => "";

        public bool Value => typeof(TEntity).GetCustomAttribute<AutoEntity>() == null;
    }

    public class CanImport<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "Import";

        public string Postfix => "";

        public bool Value => typeof(TEntity).GetCustomAttribute<AutoEntity>() == null && typeof(TEntity).HasInterface<IImportable>();
    }

    public class CanExport<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "Export";

        public string Postfix => "";

        public bool Value => false;
    }

    public class CanMerge<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "Merge";

        public string Postfix => "";

        public bool Value => typeof(TEntity).GetCustomAttribute<AutoEntity>() == null;
    }

    public class CanPost<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "Post";

        public string Postfix => "";

        public bool Value => true;
    }

    public class CanConfigurePost<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "Configure";

        public string Postfix => "Post Settings";

        public bool Value => true;
    }

    public class CanDelete<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "Delete";

        public string Postfix => "";

        public bool Value => 
            (typeof(TEntity).GetCustomAttribute<AutoEntity>() == null) && 
            (typeof(TEntity).GetInterfaces().Any(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IManyToMany<,>)));
    }

    public class CanManageIssues<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "Manage";

        public string Postfix => "Issue";

        public bool Value => (typeof(TEntity).GetCustomAttribute<AutoEntity>() == null);
    }
    
    public class CanManageProblems<TEntity> : IAutoSecurityAction<TEntity>
    {
        public string Prefix => "Manage";

        public string Postfix => "Problem";

        public bool Value => (typeof(TEntity).GetCustomAttribute<AutoEntity>() == null);
    }

    public class AutoSecurityDescriptor<TEntity, TAction> : ISecurityDescriptor
        where TEntity : Entity where TAction : IAutoSecurityAction<TEntity>, new()
    {
        private TAction _action = new TAction();

        public virtual bool Visible => true;

        public string Category => new Inflector.Inflector(new CultureInfo("en"))
            .Pluralize(
                typeof(TEntity).EntityName().Split('.').Last().SplitCamelCase()
            );

        public string Type => GetLicenseCaption();

        public virtual string Code => GetCode();

        public virtual string Description
        {
            get
            {
                var caption = GetType().GetCaption(false);
                return string.IsNullOrWhiteSpace(caption)
                    ? GetCode().SplitCamelCase()
                    : caption;
            }
        }

        public virtual bool Value => _action.Value;

        public virtual bool HasScope(SecurityDescriptorScope scope)
        {
            return true;
        }

        private string GetLicenseCaption()
        {
            var license = typeof(TEntity)
                .GetInterfaces().FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ILicense<>))
                ?.GenericTypeArguments.FirstOrDefault();
            return license != null ? license.GetCaption() : typeof(CoreLicense).GetCaption();
        }

        private string GetCode()
        {
            return string.Format(
                "Can{0}{1}{2}",
                _action.Prefix,
                string.IsNullOrWhiteSpace(_action.Postfix)
                    ? new Inflector.Inflector(new CultureInfo("en")).Pluralize(typeof(TEntity).EntityName().Split('.').Last())
                    : typeof(TEntity).EntityName().Split('.').Last(),
                string.IsNullOrWhiteSpace(_action.Postfix)
                    ? ""
                    : new Inflector.Inflector(new CultureInfo("en")).Pluralize(_action.Postfix)
            );
        }
    }
}