"""
    Quick Start
    ===========

    Installation::

       pip install flask-jwt-router


    Basic Usage::

        from flask import Flask
        from flask_jwt_router import JwtRoutes

        app = Flask(__name__)
        # You are required to always set a unique SECRET_KEY for your app
        app.config["SECRET_KEY"] = "your_app_secret_key"

        JwtRoutes(app)

        # If you're using the Flask factory pattern:
        jwt_routes = JwtRoutes()

        def create_app(config):
            ...
            jwt_routes.init_app(app)


    Authorizing Routes
    ==================

    Define as a list of tuples::

        app.config["WHITE_LIST_ROUTES"] = [
            ("POST", "/register"),
        ]

        @app.route("/register", methods=["POST"])
        def register():
            return "I don't need authorizing!"


    Prefix your api name to whitelisted routes::

        # All routes will
        app.config["JWT_ROUTER_API_NAME"] = "/api/v1"
        app.config["WHITE_LIST_ROUTES"] = [
            ("POST", "/register"),
        ]

        @app.route("/api/v1/register", methods=["POST"])
        def register():
            return "I don't need authorizing!"


    Bypass Flask-JWT-Router on specified routes::

        # Define homepage template routes for example on JWT_IGNORE_ROUTES
        # & still get to use the api name on request handlers returning resources

        app.config["IGNORED_ROUTES"] = [
            ("GET", "/")
        ]


    Declare an entity model::

        # Create your entity model (example uses Flask-SqlAlchemy)

        class UserModel(db.Model):
            __tablename__ = "users"
            id = db.Column(db.Integer, primary_key=True)
            name = db.Column(db.String)

        JwtRoutes(app, entity_models=[UserModel, TeacherModel, ...etc])

        # Or pass later with `init_app`
        def create_app(config):
            ...
            jwt_routes.init_app(app, entity_models=[UserModel, TeacherModel, ...etc])

    Setting the Token Expire Duration
    =================================

    There are two ways to set the expire duration of the JWT.

    from your app config::

        # Set the token expire duration to 7 days
        app.config["JWT_EXPIRE_DAYS"] = 7

    using the :class:`~flask_jwt_router.set_exp` method::

        # Set the token expire duration to 14 days
        jwt_routes = JwtRoutes()
        # jwt_routes.init_app( ...etc
        jwt_routes.set_exp(expire_days=14)

    By default the expire duration is set to 30 days

    Authorization & Tokens
    ======================

    From your_app import jwt_routes::

        # white list the routes
        app.config["WHITE_LIST_ROUTES"] = [
            ("POST", "/register"),
            ("POST", "/login"),
        ]

        @app.route("/register", methods=["POST"])
        def register():
            # I'm registering a new user & returning a token!
            return jsonify({
                "token": jwt_routes.create_token(entity_id=1)
            })

        @app.route("/login", methods=["POST"])
        def login():
            # I'm authorized & updating my token!
            return jsonify({
                "token": jwt_routes.update_token(entity_id=1)
            })

    Create a new entity & return a new token::

        @app.route("/register", methods=["POST"])
        def register():
            user_data = request.get_json()
            try:
                user = UserModel(**user_data)
                user.create_user() # your entity creation logic

                # Here we pass the id as a kwarg to `create_token`
                token: str = jwt_routes.create_token(entity_id=user.id, table_name="user")

                # Now we can return a new token!
                return {
                    "message": "User successfully created.",
                    "token": str(token),  # casting is optional
                }, 200

    Access entity on Flask's global context::

        from app import app, jwt_routes

        # Example uses Marshmallow to serialize entity object

        @app.route("/login" methods=["GET"])
        def login():
            user_data = g.get("entity")
            try:
                user_dumped = UserSchema().dump(user_data)
            except ValidationError as _:
               return {
                           "error": "User requested does not exist."
                       }, 401
            return {
                "data": user_dumped,
                "token": jwt_routes.create_token(entity_id=user_data.id, table_name="user"),
            }, 200

    If you are handling a request with a token in the headers you can call::

        jwt_routes.update_token(entity_id=user_data.id)

    If you are handling a request without a token in the headers you can call::

        jwt_routes.create_token(entity_id=user_data.id, table_name="user")

"""

import logging
from warnings import warn
from typing import List, Dict, Optional

from ._config import Config
from ._entity import BaseEntity, Entity, _ORMType
from ._routing import BaseRouting, RoutingMixin
from ._authentication import BaseAuthentication, Authentication
from .oauth2.google import Google
from .oauth2._base import BaseOAuth, TestBaseOAuth
from .oauth2.http_requests import HttpRequests
from .oauth2._urls import GOOGLE_OAUTH_URL

# pylint:disable=invalid-name
logger = logging.getLogger()

EXPIRE_DEFAULT = 30


class BaseJwtRoutes:
    """
    If there app is None then self.init_app(app=None, **kwargs) need to be called
    inside the Flask app factory pattern.
    :param app: Flask application instance
    :param kwargs: entity_model
    """
    #: Logging.
    logger = logging

    #: The Flask application instance.
    app = None

    #: A list of entity models
    entity_models: List[_ORMType]

    #: Low level expire member. See :class:`~flask_jwt_router._config` & set with JWT_EXPIRE_DAYS
    #: or use :class:`~flask_jwt_router.set_exp`.
    exp: int

    #: The class that is used to create Config objects.  See :class:`~flask_jwt_router._config`
    #: for more information.
    config: Config

    #: The class that provides algorithms to :class:`~flask_jwt_router._jwt_routes`.
    # See :class:`~flask_jwt_router._authentication` for more information.
    auth: BaseAuthentication

    #: The class that is used to create Entity objects.  See :class:`~flask_jwt_router._entity`
    #: for more information.
    entity: BaseEntity

    #: The class that is used to create Routing objects.  See :class:`~flask_jwt_router._routing`
    #: for more information.
    routing: BaseRouting

    #: Optional Google OAuth 2.0 Single Sign On. See :class:`~flask_jwt_router.oauth2.google``
    #: for more information.
    # google: BaseOAuth TODO remove

    #: Optional. See :class:`~flask_jwt_router.oauth2.google`
    google_oauth: Dict  # TODO needs to be a list

    #: Optional. A Lust of strategies to be implement in the routing
    strategies: List[BaseOAuth]

    #: List of instantiated strategies
    strategy_dict: Dict[str, BaseOAuth] = {}

    def __init__(self, app=None, **kwargs):
        self.entity_models = kwargs.get("entity_models")
        self.google_oauth = kwargs.get("google_oauth")
        self.strategies = kwargs.get("strategies")
        self.config = Config()
        self.auth = Authentication()
        self.app = app
        if app:
            self.init_app(app, entity_models=self.entity_models)

    def init_app(self, app=None, **kwargs):
        """
        You can use this to set up your config at runtime
        :param app: Flask application instance
        :return:
        """
        self.app = app if app else self.app
        entity_models = self.entity_models or kwargs.get("entity_models")
        self.google_oauth = self.google_oauth or kwargs.get("google_oauth")
        self.strategies = self.strategies or kwargs.get("strategies") or []
        app_config = self.get_app_config(self.app)
        if len(self.strategies):
            for S in self.strategies:
                strategy = S(HttpRequests(GOOGLE_OAUTH_URL))
                strategy.init(**self.google_oauth)
                self.strategy_dict[strategy.__class__.__name__] = strategy

        self.config.init_config(app_config, entity_models=entity_models, google_oauth=self.google_oauth)
        self.entity = Entity(self.config)
        self.routing.init(self.app, self.config, self.entity, self.strategy_dict)
        self.app.before_request(self.routing.before_middleware)
        if self.config.expire_days:
            self.exp = self.config.expire_days
        else:
            self.exp = EXPIRE_DEFAULT

    # pylint:disable=no-self-use
    def get_app_config(self, app):
        """
        :param app: Flask Application Instance
        :return: Dict[str, Any]
        """
        config = getattr(app, "config", {})
        return config

    # pylint:disable=no-self-use
    def get_entity_id(self, **kwargs):
        """
        :param kwargs: Dict[str, int]
        :return: str
        """
        try:
            return kwargs['entity_id']
        except KeyError as _:
            return None

    # pylint:disable=no-self-use
    def set_exp(self, **kwargs) -> None:
        """
        :param kwargs: Dict[str, int]
            - expire_days: The expire time for the JWT in days
        :return: None
        """
        try:
            self.exp = kwargs['expire_days']
        except KeyError as _:
            self.exp = EXPIRE_DEFAULT

    def create_token(self, **kwargs) -> str:
        """
        :param kwargs:
        :return: str
        """
        if 'entity_type' in kwargs:
            warn(("'entity_type' argument name has been deprecated and will be replaced"
                  "in the next release. Use 'table_name' instead"))
            kwargs['table_name'] = kwargs['entity_type']
        if 'table_name' not in kwargs:
            raise KeyError("create_token() missing 1 required argument: table_name")
        table_name = kwargs.get("table_name")
        self.config.entity_key = self.entity.get_attr_name(table_name)
        return self.auth.create_token(self.config, self.exp, **kwargs)

    def update_token(self, **kwargs) -> str:
        """
        :param kwargs:
        :return: str
        """
        self.config.entity_key = self.entity.get_attr_name()
        table_name = self.entity.get_entity_from_ext().__tablename__
        return self.auth.update_token(self.config, self.exp, table_name, **kwargs)

    def encode_token(self, entity_id) -> str:
        """
        :param entity_id:
        :return:
        """
        self.config.entity_key = self.entity.get_attr_name()
        table_name = self.entity.get_entity_from_ext().__tablename__
        return self.auth.encode_token(self.config, entity_id, self.exp, table_name)

    def get_strategy(self, name: str) -> Optional[BaseOAuth]:
        """
        :param name: The name of the strategy
        :return:
        """
        try:
            return self.strategy_dict[name]
        except KeyError:
            return None


class JwtRoutes(RoutingMixin, BaseJwtRoutes):
    pass

"""
    Quick Start
    ===========

    Installation::

       pip install flask-jwt-router


    Basic Usage::

        from flask import Flask
        from flask_jwt_router import JwtRoutes

        app = Flask(__name__)
        # You are required to always set a unique SECRET_KEY for your app
        app.config["SECRET_KEY"] = "your_app_secret_key"

        JwtRoutes(app)

        # If you're using the Flask factory pattern:
        jwt_routes = JwtRoutes()

        def create_app(config):
            ...
            jwt_routes.init_app(app)


    Authorizing Routes
    ==================

    Define as a list of tuples::

        app.config["WHITE_LIST_ROUTES"] = [
            ("POST", "/register"),
        ]

        @app.route("/register", methods=["POST"])
        def register():
            return "I don't need authorizing!"


    Prefix your api name to whitelisted routes::

        # All routes will
        app.config["JWT_ROUTER_API_NAME"] = "/api/v1"
        app.config["WHITE_LIST_ROUTES"] = [
            ("POST", "/register"),
        ]

        @app.route("/api/v1/register", methods=["POST"])
        def register():
            return "I don't need authorizing!"


    Bypass Flask-JWT-Router on specified routes::

        # Define homepage template routes for example on JWT_IGNORE_ROUTES
        # & still get to use the api name on request handlers returning resources

        app.config["IGNORED_ROUTES"] = [
            ("GET", "/")
        ]


    Declare an entity model::

        # Create your entity model (example uses Flask-SqlAlchemy)

        class UserModel(db.Model):
            __tablename__ = "users"
            id = db.Column(db.Integer, primary_key=True)
            name = db.Column(db.String)

        JwtRoutes(app, entity_models=[UserModel, TeacherModel, ...etc])

        # Or pass later with `init_app`
        def create_app(config):
            ...
            jwt_routes.init_app(app, entity_models=[UserModel, TeacherModel, ...etc])

    Setting the Token Expire Duration
    =================================

    There are two ways to set the expire duration of the JWT.

    from your app config::

        # Set the token expire duration to 7 days
        app.config["JWT_EXPIRE_DAYS"] = 7

    using the :class:`~flask_jwt_router.set_exp` method::

        # Set the token expire duration to 14 days
        jwt_routes = JwtRoutes()
        # jwt_routes.init_app( ...etc
        jwt_routes.set_exp(expire_days=14)

    By default the expire duration is set to 30 days

    Authorization & Tokens
    ======================

    From your_app import jwt_routes::

        # white list the routes
        app.config["WHITE_LIST_ROUTES"] = [
            ("POST", "/register"),
            ("POST", "/login"),
        ]

        @app.route("/register", methods=["POST"])
        def register():
            # I'm registering a new user & returning a token!
            return jsonify({
                "token": jwt_routes.create_token(entity_id=1)
            })

        @app.route("/login", methods=["POST"])
        def login():
            # I'm authorized & updating my token!
            return jsonify({
                "token": jwt_routes.update_token(entity_id=1)
            })

    Create a new entity & return a new token::

        @app.route("/register", methods=["POST"])
        def register():
            user_data = request.get_json()
            try:
                user = UserModel(**user_data)
                user.create_user() # your entity creation logic

                # Here we pass the id as a kwarg to `create_token`
                token: str = jwt_routes.create_token(entity_id=user.id, table_name="user")

                # Now we can return a new token!
                return {
                    "message": "User successfully created.",
                    "token": str(token),  # casting is optional
                }, 200

    Access entity on Flask's global context::

        from app import app, jwt_routes

        # Example uses Marshmallow to serialize entity object

        @app.route("/login" methods=["GET"])
        def login():
            user_data = g.get("entity")
            try:
                user_dumped = UserSchema().dump(user_data)
            except ValidationError as _:
               return {
                           "error": "User requested does not exist."
                       }, 401
            return {
                "data": user_dumped,
                "token": jwt_routes.create_token(entity_id=user_data.id, table_name="user"),
            }, 200

    If you are handling a request with a token in the headers you can call::

        jwt_routes.update_token(entity_id=user_data.id)

    If you are handling a request without a token in the headers you can call::

        jwt_routes.create_token(entity_id=user_data.id, table_name="user")

"""

import logging
from warnings import warn
from typing import List, Dict, Optional

from ._config import Config
from ._entity import BaseEntity, Entity, _ORMType
from ._routing import BaseRouting, RoutingMixin
from ._authentication import BaseAuthentication, Authentication
from .oauth2.google import Google
from .oauth2._base import BaseOAuth, TestBaseOAuth
from .oauth2.http_requests import HttpRequests
from .oauth2._urls import GOOGLE_OAUTH_URL

# pylint:disable=invalid-name
logger = logging.getLogger()

EXPIRE_DEFAULT = 30


class BaseJwtRoutes:
    """
    If there app is None then self.init_app(app=None, **kwargs) need to be called
    inside the Flask app factory pattern.
    :param app: Flask application instance
    :param kwargs: entity_model
    """
    #: Logging.
    logger = logging

    #: The Flask application instance.
    app = None

    #: A list of entity models
    entity_models: List[_ORMType]

    #: Low level expire member. See :class:`~flask_jwt_router._config` & set with JWT_EXPIRE_DAYS
    #: or use :class:`~flask_jwt_router.set_exp`.
    exp: int

    #: The class that is used to create Config objects.  See :class:`~flask_jwt_router._config`
    #: for more information.
    config: Config

    #: The class that provides algorithms to :class:`~flask_jwt_router._jwt_routes`.
    # See :class:`~flask_jwt_router._authentication` for more information.
    auth: BaseAuthentication

    #: The class that is used to create Entity objects.  See :class:`~flask_jwt_router._entity`
    #: for more information.
    entity: BaseEntity

    #: The class that is used to create Routing objects.  See :class:`~flask_jwt_router._routing`
    #: for more information.
    routing: BaseRouting

    #: Optional Google OAuth 2.0 Single Sign On. See :class:`~flask_jwt_router.oauth2.google``
    #: for more information.
    # google: BaseOAuth TODO remove

    #: Optional. See :class:`~flask_jwt_router.oauth2.google`
    google_oauth: Dict  # TODO needs to be a list

    #: Optional. A Lust of strategies to be implement in the routing
    strategies: List[BaseOAuth]

    #: List of instantiated strategies
    strategy_dict: Dict[str, BaseOAuth] = {}

    def __init__(self, app=None, **kwargs):
        self.entity_models = kwargs.get("entity_models")
        self.google_oauth = kwargs.get("google_oauth")
        self.strategies = kwargs.get("strategies")
        self.config = Config()
        self.auth = Authentication()
        self.app = app
        if app:
            self.init_app(app, entity_models=self.entity_models)

    def init_app(self, app=None, **kwargs):
        """
        You can use this to set up your config at runtime
        :param app: Flask application instance
        :return:
        """
        self.app = app if app else self.app
        entity_models = self.entity_models or kwargs.get("entity_models")
        self.google_oauth = self.google_oauth or kwargs.get("google_oauth")
        self.strategies = self.strategies or kwargs.get("strategies") or []
        app_config = self.get_app_config(self.app)
        if len(self.strategies):
            for S in self.strategies:
                strategy = S(HttpRequests(GOOGLE_OAUTH_URL))
                strategy.init(**self.google_oauth)
                self.strategy_dict[strategy.__class__.__name__] = strategy

        self.config.init_config(app_config, entity_models=entity_models, google_oauth=self.google_oauth)
        self.entity = Entity(self.config)
        self.routing.init(self.app, self.config, self.entity, self.strategy_dict)
        self.app.before_request(self.routing.before_middleware)
        if self.config.expire_days:
            self.exp = self.config.expire_days
        else:
            self.exp = EXPIRE_DEFAULT

    # pylint:disable=no-self-use
    def get_app_config(self, app):
        """
        :param app: Flask Application Instance
        :return: Dict[str, Any]
        """
        config = getattr(app, "config", {})
        return config

    # pylint:disable=no-self-use
    def get_entity_id(self, **kwargs):
        """
        :param kwargs: Dict[str, int]
        :return: str
        """
        try:
            return kwargs['entity_id']
        except KeyError as _:
            return None

    # pylint:disable=no-self-use
    def set_exp(self, **kwargs) -> None:
        """
        :param kwargs: Dict[str, int]
            - expire_days: The expire time for the JWT in days
        :return: None
        """
        try:
            self.exp = kwargs['expire_days']
        except KeyError as _:
            self.exp = EXPIRE_DEFAULT

    def create_token(self, **kwargs) -> str:
        """
        :param kwargs:
        :return: str
        """
        if 'entity_type' in kwargs:
            warn(("'entity_type' argument name has been deprecated and will be replaced"
                  "in the next release. Use 'table_name' instead"))
            kwargs['table_name'] = kwargs['entity_type']
        if 'table_name' not in kwargs:
            raise KeyError("create_token() missing 1 required argument: table_name")
        table_name = kwargs.get("table_name")
        self.config.entity_key = self.entity.get_attr_name(table_name)
        return self.auth.create_token(self.config, self.exp, **kwargs)

    def update_token(self, **kwargs) -> str:
        """
        :param kwargs:
        :return: str
        """
        self.config.entity_key = self.entity.get_attr_name()
        table_name = self.entity.get_entity_from_ext().__tablename__
        return self.auth.update_token(self.config, self.exp, table_name, **kwargs)

    def encode_token(self, entity_id) -> str:
        """
        :param entity_id:
        :return:
        """
        self.config.entity_key = self.entity.get_attr_name()
        table_name = self.entity.get_entity_from_ext().__tablename__
        return self.auth.encode_token(self.config, entity_id, self.exp, table_name)

    def get_strategy(self, name: str) -> Optional[BaseOAuth]:
        """
        :param name: The name of the strategy
        :return:
        """
        try:
            return self.strategy_dict[name]
        except KeyError:
            return None


class JwtRoutes(RoutingMixin, BaseJwtRoutes):
    pass

Quick Start     ===========      Installation::         pip install flask-jwt-router       Basic Usage::          from flask import Flask         from flask_jwt_router import JwtRoutes          app = Flask(__name__)         # You are required to always set a unique SECRET_KEY for your app         app.config["SECRET_KEY"] = "your_app_secret_key"          JwtRoutes(app)          # If you're using the Flask factory pattern:         jwt_routes = JwtRoutes()          def create_app(config):             ...             jwt_routes.init_app(app)       Authorizing Routes     ==================      Define as a list of tuples::          app.config["WHITE_LIST_ROUTES"] = [             ("POST", "/register"),         ]          @app.route("/register", methods=["POST"])         def register():             return "I don't need authorizing!"       Prefix your api name to whitelisted routes::          # All routes will         app.config["JWT_ROUTER_API_NAME"] = "/api/v1"         app.config["WHITE_LIST_ROUTES"] = [             ("POST", "/register"),         ]          @app.route("/api/v1/register", methods=["POST"])         def register():             return "I don't need authorizing!"       Bypass Flask-JWT-Router on specified routes::          # Define homepage template routes for example on JWT_IGNORE_ROUTES         # & still get to use the api name on request handlers returning resources          app.config["IGNORED_ROUTES"] = [             ("GET", "/")         ]       Declare an entity model::          # Create your entity model (example uses Flask-SqlAlchemy)          class UserModel(db.Model):             __tablename__ = "users"             id = db.Column(db.Integer, primary_key=True)             name = db.Column(db.String)          JwtRoutes(app, entity_models=[UserModel, TeacherModel, ...etc])          # Or pass later with `init_app`         def create_app(config):             ...             jwt_routes.init_app(app, entity_models=[UserModel, TeacherModel, ...etc])      Setting the Token Expire Duration     =================================      There are two ways to set the expire duration of the JWT.      from your app config::          # Set the token expire duration to 7 days         app.config["JWT_EXPIRE_DAYS"] = 7      using the :class:`~flask_jwt_router.set_exp` method::          # Set the token expire duration to 14 days         jwt_routes = JwtRoutes()         # jwt_routes.init_app( ...etc         jwt_routes.set_exp(expire_days=14)      By default the expire duration is set to 30 days      Authorization & Tokens     ======================      From your_app import jwt_routes::          # white list the routes         app.config["WHITE_LIST_ROUTES"] = [             ("POST", "/register"),             ("POST", "/login"),         ]          @app.route("/register", methods=["POST"])         def register():             # I'm registering a new user & returning a token!             return jsonify({                 "token": jwt_routes.create_token(entity_id=1)             })          @app.route("/login", methods=["POST"])         def login():             # I'm authorized & updating my token!             return jsonify({                 "token": jwt_routes.update_token(entity_id=1)             })      Create a new entity & return a new token::          @app.route("/register", methods=["POST"])         def register():             user_data = request.get_json()             try:                 user = UserModel(**user_data)                 user.create_user() # your entity creation logic                  # Here we pass the id as a kwarg to `create_token`                 token: str = jwt_routes.create_token(entity_id=user.id, table_name="user")                  # Now we can return a new token!                 return {                     "message": "User successfully created.",                     "token": str(token),  # casting is optional                 }, 200      Access entity on Flask's global context::          from app import app, jwt_routes          # Example uses Marshmallow to serialize entity object          @app.route("/login" methods=["GET"])         def login():             user_data = g.get("entity")             try:                 user_dumped = UserSchema().dump(user_data)             except ValidationError as _:                return {                            "error": "User requested does not exist."                        }, 401             return {                 "data": user_dumped,                 "token": jwt_routes.create_token(entity_id=user_data.id, table_name="user"),             }, 200      If you are handling a request with a token in the headers you can call::          jwt_routes.update_token(entity_id=user_data.id)      If you are handling a request without a token in the headers you can call::          jwt_routes.create_token(entity_id=user_data.id, table_name="user") # pylint:disable=invalid-name If there app is None then self.init_app(app=None, **kwargs) need to be called     inside the Flask app factory pattern.     :param app: Flask application instance     :param kwargs: entity_model #: Logging. #: The Flask application instance. #: A list of entity models #: Low level expire member. See :class:`~flask_jwt_router._config` & set with JWT_EXPIRE_DAYS #: or use :class:`~flask_jwt_router.set_exp`. #: The class that is used to create Config objects.  See :class:`~flask_jwt_router._config` #: for more information. #: The class that provides algorithms to :class:`~flask_jwt_router._jwt_routes`. # See :class:`~flask_jwt_router._authentication` for more information. #: The class that is used to create Entity objects.  See :class:`~flask_jwt_router._entity` #: for more information. #: The class that is used to create Routing objects.  See :class:`~flask_jwt_router._routing` #: for more information. #: Optional Google OAuth 2.0 Single Sign On. See :class:`~flask_jwt_router.oauth2.google`` #: for more information. # google: BaseOAuth TODO remove #: Optional. See :class:`~flask_jwt_router.oauth2.google` # TODO needs to be a list #: Optional. A Lust of strategies to be implement in the routing #: List of instantiated strategies You can use this to set up your config at runtime         :param app: Flask application instance         :return: # pylint:disable=no-self-use :param app: Flask Application Instance         :return: Dict[str, Any] # pylint:disable=no-self-use :param kwargs: Dict[str, int]         :return: str # pylint:disable=no-self-use :param kwargs: Dict[str, int]             - expire_days: The expire time for the JWT in days         :return: None :param kwargs:         :return: str :param kwargs:         :return: str :param entity_id:         :return: :param name: The name of the strategy         :return: