from python_helper import Constant as c
from python_helper import ReflectionHelper, ObjectHelper, log, Function, StringHelper
from python_framework.api.src.service.flask import FlaskManager
from python_framework.api.src.constant import ConfigurationKeyConstant
from python_framework.api.src.converter.static import ConverterStatic


DEFAUTL_MUTE_LOGS = False
DEFAUTL_ENABLED = True


@Function
def Listener(*listenerArgs, manager=None, managerClient=None, enabled=DEFAUTL_ENABLED, muteLogs=DEFAUTL_MUTE_LOGS, **listenerKwargs) :
    listenerManager = manager
    listenerManagerClient = managerClient
    def Wrapper(OuterClass, *args, **kwargs):
        log.wrapper(Listener,f'''wrapping {OuterClass.__name__}''')
        class InnerClass(OuterClass):
            def __init__(self,*args,**kwargs):
                log.wrapper(OuterClass,f'in {InnerClass.__name__}.__init__(*{args},**{kwargs})')
                apiInstance = FlaskManager.getApi()
                OuterClass.__init__(self,*args,**kwargs)
                self.manager = listenerManager if not isinstance(listenerManager, str) else ReflectionHelper.getAttributeOrMethodByNamePath(apiInstance, listenerManager)
                self.managerClient = listenerManagerClient if not isinstance(listenerManagerClient, str) else ReflectionHelper.getAttributeOrMethodByNamePath(apiInstance, listenerManagerClient)
                self.globals = apiInstance.globals
                self.service = apiInstance.resource.service
                self.enabled = enabled and self.globals.getApiSetting(ConfigurationKeyConstant.API_LISTENER_ENABLE)
                self.muteLogs = muteLogs or ConverterStatic.getValueOrDefault(self.globals.getApiSetting(ConfigurationKeyConstant.API_LISTENER_MUTE_LOGS), DEFAUTL_MUTE_LOGS and muteLogs)
        ReflectionHelper.overrideSignatures(InnerClass, OuterClass)
        return InnerClass
    return Wrapper


@Function
def ListenerMethod(
    *methodArgs,
    requestClass = None,
    interceptor = FlaskManager.defaultResourceInterceptor,
    enabled = DEFAUTL_ENABLED,
    muteLogs = DEFAUTL_MUTE_LOGS,
    **methodKwargs
):
    resourceMethodEnabled = enabled
    resourceMethodMuteLogs = muteLogs
    resourceInterceptor = interceptor
    def innerMethodWrapper(resourceMethod, *innerMethodArgs, **innerMethodKwargs) :
        log.wrapper(ListenerMethod,f'''wrapping {resourceMethod.__name__}''')
        apiInstance = FlaskManager.getApi()
        methodClassName = ReflectionHelper.getMethodClassName(resourceMethod)
        methodName = ReflectionHelper.getName(resourceMethod)
        resourceTypeIsEnabled = apiInstance.globals.getApiSetting(ConfigurationKeyConstant.API_LISTENER_ENABLE)
        resourceMethod.enabled = resourceMethodEnabled and resourceTypeIsEnabled
        resourceMethod.id = methodKwargs.get('id', f'{methodClassName}{c.DOT}{methodName}')
        resourceMethod.muteLogs = resourceMethodMuteLogs or ConverterStatic.getValueOrDefault(apiInstance.globals.getApiSetting(ConfigurationKeyConstant.API_LISTENER_MUTE_LOGS), DEFAUTL_MUTE_LOGS and resourceMethodMuteLogs)
        listenerArgs = [*methodArgs]
        listenerKwargs = {**methodKwargs}
        resourceInstanceName = methodClassName[:-len(FlaskManager.KW_LISTENER_RESOURCE)]
        resourceInstanceName = f'{resourceInstanceName[0].lower()}{resourceInstanceName[1:]}'
        interceptor = resourceInterceptor if not isinstance(resourceInterceptor, str) else  ReflectionHelper.getAttributeOrMethodByNamePath(apiInstance, resourceInterceptor)
        @interceptor(*listenerArgs, **listenerKwargs)
        def innerResourceInstanceMethod(*args, **kwargs) :
            resourceInstance = FlaskManager.getResourceSelf(apiInstance, FlaskManager.KW_LISTENER_RESOURCE, resourceInstanceName)
            args = FlaskManager.getArgumentInFrontOfArgs(args, resourceInstance) ###- resourceInstance = args[0]
            muteLogs = resourceInstance.muteLogs or resourceMethod.muteLogs
            if resourceInstance.enabled and resourceMethod.enabled:
                if not muteLogs:
                    log.info(resourceMethod, f'{resourceMethod.id} listener method started with args={methodArgs} and kwargs={methodKwargs}')
                methodReturn = None
                try :
                    FlaskManager.validateArgs(args,requestClass,innerResourceInstanceMethod)
                    methodReturn = resourceMethod(*args,**kwargs)
                except Exception as exception :
                    if not muteLogs:
                        log.warning(resourceMethod, f'Not possible to run {resourceMethod.id} properly', exception=exception, muteStackTrace=True)
                    FlaskManager.raiseAndPersistGlobalException(exception, resourceInstance, resourceMethod)
                if not muteLogs:
                    log.info(resourceMethod, f'{resourceMethod.id} listener method finished')
                return methodReturn
            else:
                if not muteLogs:
                    log.warning(resourceMethod, f'{resourceMethod.id} listener method didn{c.SINGLE_QUOTE}t started. {"Listeners are disabled" if resourceTypeIsEnabled else "This listener class is disabled" if not resourceInstance.enabled else "This listener method is disabled"}')
        ReflectionHelper.overrideSignatures(innerResourceInstanceMethod, resourceMethod)
        innerResourceInstanceMethod.enabled = resourceMethodEnabled
        innerResourceInstanceMethod.muteLogs = resourceMethodMuteLogs
        innerResourceInstanceMethod.interceptor = resourceInterceptor
        return innerResourceInstanceMethod
    return innerMethodWrapper
