class WedeliverCorePlus:
    """
    Singleton class for WedeliverCorePlus
    """
    __app = None

    @staticmethod
    def get_app():
        """ Static access method. """
        if WedeliverCorePlus.__app is None:
            WedeliverCorePlus()
        return WedeliverCorePlus.__app

    def __init__(self, app=None):
        """ Virtually private constructor. """
        if WedeliverCorePlus.__app is not None:
            raise Exception("This class is a singleton!")
        else:
            WedeliverCorePlus.__app = app
            _setup_default_routes(app)
            _setup_babel_locale(app)


def _setup_babel_locale(app):
    if 'babel' not in app.extensions:
        return

    from flask import request
    from wedeliver_core_plus.helpers.auth import Auth
    babel = app.extensions['babel']

    @babel.localeselector
    def get_locale():
        """
        This function is used to determine the language to use for translations.
        """
        # if a user is logged in, use the locale from the user settings
        user = Auth.get_user()

        language = user.get('language')
        if language:
            return language
        # otherwise try to guess the language from the user accept
        # header the browser transmits. The best match wins.
        return request.accept_languages.best_match(['ar', 'en'])


def _process_cache_registration_metadata(metadata_list):
    """
    Process cache registration metadata from upstream services.

    1. Store metadata in Flask g object for downstream MicroFetcher calls (chaining)
    2. Register cross-service invalidation listeners for models in THIS service

    Args:
        metadata_list: List of cache metadata dictionaries from upstream services
            Each metadata dict contains:
                - service_name: Source service name
                - api_path: API path to invalidate
                - scoped_cache_keys: Cache key structure
                - cross_service_models: Dict of {model_name: conditions}
    """
    from flask import g
    from wedeliver_core_plus.helpers.caching.cache_invalidation_registry import register_model_invalidation

    # Store in g object for downstream calls (chaining)
    if not hasattr(g, '_cache_registration_metadata'):
        g._cache_registration_metadata = []
    g._cache_registration_metadata.extend(metadata_list)

    # Register invalidation listeners for models in THIS service
    for metadata in metadata_list:
        cross_service_models = metadata.get("cross_service_models", {})

        if cross_service_models:
            source_service = metadata["service_name"]
            api_path = metadata["api_path"]
            scoped_cache_keys = metadata["scoped_cache_keys"]

            # Register each model using unified function
            for model_name, conditions in cross_service_models.items():
                register_model_invalidation(
                    model_name=model_name,  # Just the name (e.g., "Customer")
                    conditions=conditions,
                    cache_rule_instance=None,  # Cross-service
                    source_service=source_service,
                    api_path=api_path,
                    scoped_cache_keys=scoped_cache_keys
                )


def _setup_default_routes(app):
    from wedeliver_core_plus.app_decorators.app_entry import route
    from wedeliver_core_plus.helpers.fetch_relational_data import fetch_relational_data
    import os

    @route(
        path='/',
        require_auth=False
    )
    def _health_check_service():
        return dict(name="{} Service".format(app.config.get('SERVICE_NAME')), works=True)

    @route(
        path='/health_check',
        require_auth=False
    )
    def _health_check_with_path_service():
        return dict(name="{} Service".format(app.config.get('SERVICE_NAME')), works=True)

    @route("/fetch_relational_data", methods=["POST"], require_auth=False)
    def _fetch_relational_data_service(validated_data):
        """
        Receives MicroFetcher requests and processes cache registration metadata.
        """
        # Extract and process cache metadata
        cache_metadata_key = '__cache_registration_metadata__'
        if validated_data.get(cache_metadata_key):
            _process_cache_registration_metadata(validated_data.get(cache_metadata_key))

        # Extract user auth data
        user_data_key = '__user_auth_data__'
        if validated_data.get(user_data_key) is not None:
            from wedeliver_core_plus.helpers.auth import Auth
            Auth.set_user(validated_data.get(user_data_key))

        # Clean up metadata from validated_data
        validated_data.pop(cache_metadata_key, None)
        validated_data.pop(user_data_key, None)

        return fetch_relational_data(**validated_data)

    @route(
        path='/health/cache',
        methods=['GET'],
        require_auth=False
    )
    def _cache_health_check():
        """
        Health check endpoint for cache system.

        Returns:
            dict: Cache system status and metrics (200 OK)

        Raises:
            AppSilentException: Cache system degraded (503) or unhealthy (500)
        """
        from wedeliver_core_plus.helpers.exceptions import AppSilentException

        try:
            from wedeliver_core_plus.helpers.caching.valkey_redis_utils import BaseCacheRule
            from wedeliver_core_plus.helpers.caching.cache_invalidation_registry import (
                _unified_registry,
                _listeners_registered,
                _event_pool,
                _event_pool_initialized,
                GEVENT_AVAILABLE
            )

            health_status = {
                "status": "healthy",
                "worker_pid": os.getpid(),
                "gevent_available": GEVENT_AVAILABLE,
                "redis": {},
                "event_pool": {},
                "invalidation_pool": {},
                "registry": {},
            }

            # Check Redis connection
            if BaseCacheRule._redis_client is not None:
                try:
                    BaseCacheRule._redis_client.ping()
                    health_status["redis"] = {
                        "status": "connected",
                        "client_initialized": True
                    }
                except Exception as e:
                    health_status["status"] = "degraded"
                    health_status["redis"] = {
                        "status": "error",
                        "error": str(e),
                        "client_initialized": True
                    }
            else:
                health_status["status"] = "degraded"
                health_status["redis"] = {
                    "status": "not_initialized",
                    "client_initialized": False
                }

            # Check event pool
            if _event_pool_initialized and _event_pool is not None:
                pool_type = "gevent" if GEVENT_AVAILABLE else "thread"
                health_status["event_pool"] = {
                    "status": "initialized",
                    "type": pool_type,
                    "initialized": True
                }
            else:
                health_status["event_pool"] = {
                    "status": "not_initialized",
                    "initialized": False
                }

            # Check invalidation pool
            if BaseCacheRule._invalidation_pool_initialized and BaseCacheRule._invalidation_pool is not None:
                pool_type = "gevent" if GEVENT_AVAILABLE else "thread"
                health_status["invalidation_pool"] = {
                    "status": "initialized",
                    "type": pool_type,
                    "initialized": True
                }
            else:
                health_status["invalidation_pool"] = {
                    "status": "not_initialized",
                    "initialized": False
                }

            # Registry statistics
            health_status["registry"] = {
                "models_registered": len(_unified_registry),
                "listeners_registered": len(_listeners_registered),
                "model_names": [model.__name__ for model in _unified_registry.keys()]
            }

            # Check if system is degraded and raise exception
            if health_status["redis"]["status"] != "connected":
                exception = AppSilentException(
                    f"Cache system degraded: Redis {health_status['redis']['status']}"
                )
                exception.code = 503
                raise exception

            # Success - return data only (no status code)
            return health_status

        except AppSilentException:
            # Re-raise our custom exceptions
            raise
        except Exception as e:
            # Unexpected errors - raise as 503 Service Unavailable
            exception = AppSilentException(
                f"Cache health check failed: {str(e)}"
            )
            exception.code = 503
            raise exception

    @route(
        path='/health/cache/registry',
        methods=['GET'],
        require_auth=False
    )
    def _cache_registry_details():
        """
        Detailed cache registry information for debugging.

        Returns:
            dict: Detailed registry information (200 OK)

        Raises:
            AppSilentException: Registry retrieval failed (500)
        """
        from wedeliver_core_plus.helpers.exceptions import AppSilentException

        try:
            from wedeliver_core_plus.helpers.caching.cache_invalidation_registry import (
                _unified_registry,
                _listeners_registered
            )

            registry_details = {
                "worker_pid": os.getpid(),
                "total_models": len(_unified_registry),
                "total_listeners": len(_listeners_registered),
                "models": {}
            }

            # Build detailed model information
            for model_class, rules in _unified_registry.items():
                model_name = model_class.__name__
                registry_details["models"][model_name] = {
                    "local_rules_count": len(rules.get("local_rules", [])),
                    "cross_service_rules_count": len(rules.get("cross_service_rules", [])),
                    "local_rules": [
                        {
                            "path": rule.path,
                            "ttl_seconds": rule.ttl.total_seconds() if hasattr(rule.ttl, 'total_seconds') else None
                        }
                        for rule in rules.get("local_rules", [])
                    ],
                    "cross_service_rules": [
                        {
                            "source_service": rule["source_service"],
                            "api_path": rule["api_path"]
                        }
                        for rule in rules.get("cross_service_rules", [])
                    ]
                }

            # Listener information
            registry_details["listeners"] = [
                {
                    "model": model_class.__name__,
                    "events": list(events)
                }
                for model_class, events in _listeners_registered
            ]

            # Success - return data only (no status code)
            return registry_details

        except Exception as e:
            # Unexpected errors - raise as 500 Internal Server Error
            raise AppSilentException(
                f"Cache registry details failed: {str(e)}"
            )
