'''
This Module contains Generic abstract classes.
'''

from abc import ABCMeta, abstractmethod
from typing import cast, Any, TypeVar
# from celery import Task


abs_attr_type = TypeVar('abs_attr_type')

class DummyAttribute:
	'''
	A Dummy Type for abstract_attribute to return.
	'''
	pass

def abstract_attribute(obj = None, type_ = Any) -> abs_attr_type:
	'''
	Use this to make abstract attributes of given type.

	____________________________________________________________________________

	Arguments:

		obj : Any 	->	It takes the object when using it as a decorator.

		type_ : Any	->	Provide the type of variable you want to declear.
		(Default = Any)
	'''
	_obj = cast(type_, obj)
	if obj is None:
		_obj = DummyAttribute()
	_obj.__is_abstract_attribute__ = True  # type: ignore
	return cast(abs_attr_type, _obj)


class MyABCMeta(ABCMeta):

    def __call__(cls, *args, **kwargs):
        instance = ABCMeta.__call__(cls, *args, **kwargs)
        abstract_attributes = {
            name
            for name in dir(instance)
            if getattr(getattr(instance, name), '__is_abstract_attribute__', False)
        }
        if abstract_attributes:
            raise NotImplementedError(
                "Can't instantiate abstract class {} with"
                " abstract attributes: {}".format(
                    cls.__name__,
                    ', '.join(abstract_attributes)
                )
            )
#         return instance

# class GenericCeleryTask(Task,metaclass=MyABCMeta):
# 	'''
# 	This is a Abstract Class for implementation of Classs-Based
# 	Celery Tasks for MNF.

# 	It contains all the necessary methods that must be implemented
# 	by and any class inheriting it to be in-lined with the integration.

# 	Do read the doc-scrings of each method for insites.

# 	____________________________________________________________________________

# 	This Class itself inherits from Task which is the main Class for
# 	celery class-bases task implementation.

# 	For reference of implementation of GenericCeleryTask, checkout neutralAudit
# 	/tasks.py.

# 	____________________________________________________________________________

# 	By Amulya Paritosh
# 	'''

# 	track_started = True
# 	'''
# 	If enabled the task will report its status as 'started' when the task
#     is executed by a worker.  Disabled by default as the normal behavior
#     is to not report that level of granularity.  Tasks are either pending,
#     finished, or waiting to be retried.
# 	'''

# 	name : str = abstract_attribute(type_ = str)
# 	'''
# 	This is an attribute which must be defined.

# 	`name = <app_name.module.class>`
# 	'''

# 	soft_time_limit : int = abstract_attribute(type_ = int)
# 	'''
# 	This is an attribute which must be defined.

# 	This is the time limit for which the task will run. If this time limit
# 	is exceeded, SoftTimeLimitExceeded error will be raised.
# 	'''


# 	@abstractmethod
# 	def to_run(self) -> bool:
# 		'''
# 		Put logic of checking if the queued task is to be run or not.

# 		This to_run function is the part of 2nd block of `run()` method (check out
# 		 `run()` method to know more about the logic blocks of running the task).

# 		This method must be called in `run()` method.
# 		'''
# 		...

# 	@abstractmethod
# 	def after_return(self, status, retval, task_id, args, kwargs, einfo) -> None:
# 		'''
# 		Handler called after the task returns.

# 		This method is called when the task returns irrespective of its success or
# 		 failure.

# 		Can be used for freeing resources and deleting objects.

# 		____________________________________________________________________________

# 		Arguments:

# 			status (str): Current task state.

# 			retval (Any): Task return value/exception.

# 			task_id (str): Unique id of the task.

# 			args (Tuple): Original arguments for the task.

# 			kwargs (Dict): Original keyword arguments for the task.

# 			einfo (~billiard.einfo.ExceptionInfo): Exception information.

# 		____________________________________________________________________________

# 		Returns:

# 			None: The return value of this handler is ignored.
#         '''
# 		...

# 	@abstractmethod
# 	def on_failure(self, exc, task_id, args, kwargs, einfo) -> None:
# 		'''
# 		Error handler.

# 		This is run by the worker when the task fails.

# 		Put a control for expected exceptions here for their special handling.
# 		Check with `is_expected_exceptions()` static classmethod.

# 		____________________________________________________________________________

# 		Arguments:

# 			exc (Exception): The exception raised by the task.

# 			task_id (str): Unique id of the failed task.

# 			args (Tuple): Original arguments for the task that failed.

# 			kwargs (Dict): Original keyword arguments for the task that failed.

# 			einfo (~billiard.einfo.ExceptionInfo): Exception information.

# 		____________________________________________________________________________

# 		Returns:
# 			None: The return value of this handler is ignored.
#         '''
# 		...

# 	@abstractmethod
# 	def on_success(self, retval, task_id, args, kwargs) -> None:
# 		'''
# 		Success handler.

# 		Run by the worker if the task executes successfully.

# 		____________________________________________________________________________

# 		Arguments:

# 			retval (Any): The return value of the task.

# 			task_id (str): Unique id of the executed task.

# 			args (Tuple): Original arguments for the executed task.

# 			kwargs (Dict): Original keyword arguments for the executed task.

# 		____________________________________________________________________________

# 		Returns:
# 			None: The return value of this handler is ignored.
#         '''
# 		...

# 	@abstractmethod
# 	def on_retry(self, exc, task_id, args, kwargs, einfo) -> None:
# 		'''
# 		Retry handler.

# 		This is run by the worker when the task is to be retried.

# 		____________________________________________________________________________

# 		Arguments:

# 			exc (Exception): The exception sent to :meth:`retry`.

# 			task_id (str): Unique id of the retried task.

# 			args (Tuple): Original arguments for the retried task.

# 			kwargs (Dict): Original keyword arguments for the retried task.

# 			einfo (~billiard.einfo.ExceptionInfo): Exception information.

# 		____________________________________________________________________________

# 		Returns:
# 			None: The return value of this handler is ignored.
#         '''
# 		...

# 	@abstractmethod
# 	def run(self, *args, **kwargs) -> None:
# 		'''
# 		The body of the task executed by workers. Here write the main code blocks to
# 		 be run.

# 		The Logic should be written in 3 blocks (its just a convention)

# 			block1 : initialization of certian required fields.

# 			block2 : check if to go ahed with the execution with to_run() method.

# 			block3 : main block of the code to run.
# 		'''
# 		...

# 	@classmethod
# 	def is_expected_exceptions(cls, exc) -> bool:
# 		'''
# 		This checks if the provided exception was expected or not.
# 		____________________________________________________________________________

# 		Returns :
# 			bool
# 		'''
# 		return isinstance(exc, cls.throws)


class ABCFileType(metaclass=MyABCMeta):
    """
    All FileTypes to inherit it.
    Contains some must have attributes.
    """
    allowed_extentions : tuple = abstract_attribute(type_ = tuple)

    def validate() -> bool:
        return True