using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Models.Permissions
{
	/// 
	/// The kind of permission needed.
	/// 
	public enum Kind
	{
		Read,
		Write,
		Create,
		Delete
	}
	/// 
	/// The group of the permission.
	/// 
	public enum Group
	{
		Overall,
		Admin
	}
	
	/// 
	/// Specify permissions needed for the API.
	/// 
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
	public class PermissionAttribute : Attribute, IFilterFactory
	{
		/// 
		/// The needed permission as string.
		/// 
		public string Type { get; }
		/// 
		/// The needed permission kind.
		/// 
		public Kind Kind { get; }
		/// 
		/// The group of this permission
		/// 
		public Group Group { get; }
		/// 
		/// Ask a permission to run an action. 
		/// 
		/// 
		/// The type of the action
		/// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
		/// 
		/// The kind of permission needed
		/// 
		/// The group of this permission (allow grouped permission like overall.read
		/// for all read permissions of this group)
		/// 
		public PermissionAttribute(string type, Kind permission, Group group = Group.Overall)
		{
			if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
				type = type[..^3];
			Type = type.ToLower();
			Kind = permission;
			Group = group;
		}
		
		/// 
		public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
		{
			return serviceProvider.GetRequiredService().Create(this);
		}
		/// 
		public bool IsReusable => true;
		/// 
		/// Return this permission attribute as a string
		/// 
		/// The string representation.
		public string AsPermissionString()
		{
			return Type;
		}
	}
	/// 
	/// Specify one part of a permissions needed for the API (the kind or the type).
	/// 
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
	public class PartialPermissionAttribute : Attribute, IFilterFactory
	{
		/// 
		/// The needed permission type.
		/// 
		public string Type { get; }
		/// 
		/// The needed permission kind.
		/// 
		public Kind Kind { get; }
		
		/// 
		/// Ask a permission to run an action. 
		/// 
		/// 
		/// With this attribute, you can only specify a type or a kind.
		/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
		/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
		/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
		/// lead to unspecified behaviors. 
		/// 
		/// 
		/// The type of the action
		/// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
		/// 
		public PartialPermissionAttribute(string type)
		{
			if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
				type = type[..^3];
			Type = type.ToLower();
		}
		
		/// 
		/// Ask a permission to run an action. 
		/// 
		/// 
		/// With this attribute, you can only specify a type or a kind.
		/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
		/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
		/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
		/// lead to unspecified behaviors. 
		/// 
		/// The kind of permission needed
		public PartialPermissionAttribute(Kind permission)
		{
			Kind = permission;
		}
		
		/// 
		public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
		{
			return serviceProvider.GetRequiredService().Create(this);
		}
		/// 
		public bool IsReusable => true;
	}
	/// 
	/// A service to validate permissions
	/// 
	public interface IPermissionValidator
	{
		/// 
		/// Create an IAuthorizationFilter that will be used to validate permissions.
		/// This can registered with any lifetime.
		/// 
		/// The permission attribute to validate
		/// An authorization filter used to validate the permission
		IFilterMetadata Create(PermissionAttribute attribute);
		
		/// 
		/// Create an IAuthorizationFilter that will be used to validate permissions.
		/// This can registered with any lifetime.
		/// 
		/// 
		/// A partial attribute to validate. See .
		/// 
		/// An authorization filter used to validate the permission
		IFilterMetadata Create(PartialPermissionAttribute attribute);
	}
}