
import traceback
import configuration
from datetime import datetime
import inspect

from bravaweb.utils.log import *

def ValidRequestParams(environment, action, klass):

    params = {}
    errors = []
    annotations = action.__annotations__

    # WHILE DECORATOR, GET ENCAPSULATE FUNCTION
    if "return" in annotations:
        try:
            # If it's a decorator, it usually has a function name containing 'decorator'
            # We follow the chain of decorators to find the actual function
            while hasattr(annotations["return"], "__name__") and "decorator" in annotations["return"].__name__:
                if hasattr(annotations["return"], "__annotations__"):
                    annotations = annotations["return"].__annotations__
                else:
                    break

            # If the current 'return' itself has annotations (e.g. it's the wrapped function), use them
            if hasattr(annotations["return"], "__annotations__"):
                annotations = dict(annotations["return"].__annotations__)
        except Exception:
            pass

        # SET ENVIRONMENT RESPONSE TYPE
        if "return" in annotations:
            environment.response_type = annotations["return"]

        # REMOVE RETURN FROM REQUIRED PARAMS
        try:
            del annotations["return"]
        except Exception as e:
            pass

        # GET DEFAULTS
        try:
            sig = inspect.signature(action)
            action_params = sig.parameters
        except ValueError:
            action_params = {}

        # GET REQUIRED PARAM IN REQUEST
        for param, instance in annotations.items():
            has_default = param in action_params and action_params[param].default != inspect.Parameter.empty
            
            if param not in environment.request:
                if not has_default:
                    errors.append(
                        "Field [{}] not present in the request".format(param))
            else:
                try:
                    instance_name = getattr(instance, "__name__", "")
                    if isinstance(environment.request[param], dict):
                        params[param] = instance(**environment.request[param])
                    elif instance_name == "bool" and isinstance(environment.request[param], str):
                        params[param] = environment.request[param].lower() in ['true', '1']
                    elif instance_name == "datetime" and isinstance(environment.request[param], str):
                        params[param] = datetime.strptime(environment.request[param], configuration.api.date_format)
                    else:
                        try:
                            params[param] = instance(environment.request[param])
                        except TypeError:
                            # Se a tipagem falhar (ex: typing.List), preserva o dado bruto
                            params[param] = environment.request[param]
                except ValueError:
                    errors.append("Invalid value for [{}] field".format(param))
                except Exception as e:
                    errors.append("Unexpected [{}] field: {}".format(param, str(e)))

        if len(errors) > 0:
            Error("Parameter Validation", "\n".join(errors), traceback=False)

    return params, errors
