"""
Base App class for Gateway implementations in the Solace AI Connector.
"""

import uuid
from abc import abstractmethod
from typing import Any, Dict, List, Type, Optional, Literal

from pydantic import Field, ValidationError
from solace_ai_connector.common.log import log
from solace_ai_connector.common.utils import deep_merge
from solace_ai_connector.flow.app import App
from solace_ai_connector.components.component_base import ComponentBase

from ...common.utils.pydantic_utils import SamConfigBase
from ...common.a2a import (
    get_discovery_topic,
    get_gateway_response_subscription_topic,
    get_gateway_status_subscription_topic,
)


class BaseGatewayComponent(ComponentBase):
    pass


class BaseGatewayAppConfig(SamConfigBase):
    """Base Pydantic model for gateway application configuration."""

    namespace: str = Field(
        ...,
        description="Absolute topic prefix for A2A communication (e.g., 'myorg/dev').",
    )
    gateway_id: Optional[str] = Field(
        default=None,
        description="Unique ID for this gateway instance. Auto-generated if omitted.",
    )
    artifact_service: Dict[str, Any] = Field(
        ...,
        description="Configuration for the SHARED ADK Artifact Service.",
    )
    enable_embed_resolution: bool = Field(
        default=True,
        description="Enable late-stage 'artifact_content' embed resolution in the gateway.",
    )
    gateway_max_artifact_resolve_size_bytes: int = Field(
        default=104857600,  # 100MB
        description="Maximum size of an individual artifact's raw content for 'artifact_content' embeds and max total accumulated size for a parent artifact after internal recursive resolution.",
    )
    gateway_recursive_embed_depth: int = Field(
        default=12,
        description="Maximum depth for recursively resolving 'artifact_content' embeds within files.",
    )
    artifact_handling_mode: Literal["reference", "embed", "passthrough"] = Field(
        default="reference",
        description=(
            "How the gateway handles file parts from clients. "
            "'reference': Save inline file bytes to the artifact store and replace with a URI. "
            "'embed': Resolve file URIs and embed content as bytes. "
            "'passthrough': Send file parts to the agent as-is."
        ),
    )
    gateway_max_message_size_bytes: int = Field(
        default=10_000_000,  # 10MB
        description="Maximum allowed message size in bytes for messages published by the gateway.",
    )
    default_user_identity: Optional[str] = Field(
        default=None,
        description="Default user identity to use when no user authentication is provided. WARNING: Only use in development environments with trusted access!",
    )
    force_user_identity: Optional[str] = Field(
        default=None,
        description="Override any provided user identity with this value. WARNING: Development only! This completely replaces authentication.",
    )
    identity_service: Optional[Dict[str, Any]] = Field(
        default=None,
        description="Configuration for the pluggable Identity Service provider.",
    )


class BaseGatewayApp(App):
    """
    Base class for Gateway applications.

    Handles common configuration, Solace broker setup, and instantiation
    of the gateway-specific component.
    """

    # This is now a placeholder. Validation is handled by Pydantic models in subclasses.
    app_schema: Dict[str, List[Dict[str, Any]]] = {"config_parameters": []}
    SPECIFIC_APP_SCHEMA_PARAMS_ATTRIBUTE_NAME = "SPECIFIC_APP_SCHEMA_PARAMS"

    def __init__(self, app_info: Dict[str, Any], gateway_app_config=BaseGatewayAppConfig, **kwargs):
        """
        Initializes the BaseGatewayApp.

        Args:
            app_info: Configuration dictionary for the app, typically from YAML.
            **kwargs: Additional arguments for the parent App class.
        """
        log.debug(
            "Initializing BaseGatewayApp with app_info: %s",
            app_info.get("name", "Unnamed App"),
        )

        code_config_app_block = getattr(self.__class__, "app_config", {}).get(
            "app_config", {}
        )
        yaml_app_config_block = app_info.get("app_config", {})
        resolved_app_config_block = deep_merge(
            code_config_app_block, yaml_app_config_block
        )

        try:
            # Validate the configuration against the base model
            validated_config = gateway_app_config.model_validate_and_clean(
                resolved_app_config_block
            )
            # Use the validated model's dict representation
            resolved_app_config_block = validated_config
        except ValidationError as e:
            log.error("Base Gateway configuration validation failed:\n%s", e)
            raise ValueError(f"Invalid Base Gateway configuration: {e}") from e

        self.namespace: str = resolved_app_config_block.get("namespace")
        if not self.namespace:
            raise ValueError(
                "Namespace is required in app_config for BaseGatewayApp or its derivatives."
            )

        self.gateway_id: str = resolved_app_config_block.get("gateway_id")
        if not self.gateway_id:
            self.gateway_id = f"gdk-gateway-{uuid.uuid4().hex[:8]}"
            resolved_app_config_block["gateway_id"] = self.gateway_id
            log.info("Generated unique gateway_id: %s", self.gateway_id)

        self.artifact_service_config: Dict = resolved_app_config_block.get(
            "artifact_service", {}
        )
        self.enable_embed_resolution: bool = resolved_app_config_block.get(
            "enable_embed_resolution", True
        )

        new_size_limit_key = "gateway_max_artifact_resolve_size_bytes"
        default_new_size_limit = 104857600
        old_size_limit_key = "gateway_artifact_content_limit_bytes"

        new_value = resolved_app_config_block.get(new_size_limit_key)
        old_value = resolved_app_config_block.get(old_size_limit_key)

        app_name_for_log = app_info.get("name", "BaseGatewayApp")

        if new_value is not None:
            self.gateway_max_artifact_resolve_size_bytes = new_value
            if old_value is not None and new_value != old_value:
                log.warning(
                    f"[{app_name_for_log}] Both '{new_size_limit_key}' (value: {new_value}) and deprecated '{old_size_limit_key}' (value: {old_value}) are present. "
                    f"Using value from '{new_size_limit_key}'."
                )
        elif old_value is not None:
            self.gateway_max_artifact_resolve_size_bytes = old_value
            log.warning(
                f"[{app_name_for_log}] Configuration key '{old_size_limit_key}' (value: {old_value}) is deprecated. "
                f"Please use '{new_size_limit_key}'. Using value from old key."
            )
        else:
            self.gateway_max_artifact_resolve_size_bytes = default_new_size_limit

        self.gateway_recursive_embed_depth: int = resolved_app_config_block.get(
            "gateway_recursive_embed_depth", 12
        )
        self.artifact_handling_mode: str = resolved_app_config_block.get(
            "artifact_handling_mode", "reference"
        )
        self.gateway_max_message_size_bytes: int = resolved_app_config_block.get(
            "gateway_max_message_size_bytes", 10_000_000
        )

        modified_app_info = app_info.copy()
        modified_app_info["app_config"] = resolved_app_config_block

        subscriptions = [
            {"topic": get_discovery_topic(self.namespace)},
            {
                "topic": get_gateway_response_subscription_topic(
                    self.namespace, self.gateway_id
                )
            },
            {
                "topic": get_gateway_status_subscription_topic(
                    self.namespace, self.gateway_id
                )
            },
        ]
        log.info(
            "Generated Solace subscriptions for gateway '%s': %s",
            self.gateway_id,
            subscriptions,
        )

        gateway_component_class = self._get_gateway_component_class()
        if not gateway_component_class or not issubclass(
            gateway_component_class, ComponentBase
        ):
            raise TypeError(
                f"_get_gateway_component_class in {self.__class__.__name__} must return a valid ComponentBase subclass."
            )

        component_definition = {
            "name": f"{self.gateway_id}_component",
            "component_class": gateway_component_class,
            "component_config": {"app_config": resolved_app_config_block},
            "subscriptions": subscriptions,
        }
        modified_app_info["components"] = [component_definition]

        broker_config = modified_app_info.setdefault("broker", {})
        broker_config["input_enabled"] = True
        broker_config["output_enabled"] = True
        broker_config["queue_name"] = (
            f"{self.namespace.strip('/')}/q/gdk/gateway/{self.gateway_id}"
        )
        broker_config["temporary_queue"] = True
        log.debug(
            "Injected broker settings for gateway '%s': %s",
            self.gateway_id,
            broker_config,
        )

        super().__init__(app_info=modified_app_info, **kwargs)
        log.info("BaseGatewayApp '%s' initialized successfully.", self.name)

    @abstractmethod
    def _get_gateway_component_class(self) -> Type[BaseGatewayComponent]:
        """
        Abstract method to be implemented by derived gateway applications.

        Returns:
            The specific gateway component class (e.g., WebUIBackendComponent).
        """
        pass
