"""Shared service for processing UI components in static and LLM modes."""

from typing import Any

from agent_flows.core.runtime.variable_interpolator import VariableInterpolator
from agent_flows.exceptions import ExecutorError
from agent_flows.integrations import LLMProviderManager
from agent_flows.models.execution import ExecutionContext
from agent_flows.services.llm import LLMRequest, LLMService
from agent_flows.services.ui.models import UIComponentDataType, UIComponentRequest
from agent_flows.utils.logging import get_logger

log = get_logger(__name__)


class UIComponentProcessor:
    """Service for processing UI components with static or LLM-based generation."""

    def __init__(self) -> None:
        """Initialize the UI component processor."""
        self.interpolator = VariableInterpolator()
        self.llm_service = LLMService()

    async def process(
        self,
        request: UIComponentRequest,
        context: ExecutionContext,
    ) -> dict[str, Any]:
        """Process UI component data based on configuration mode."""
        if request.use_llm:
            return await self._process_llm_mode(request, context)
        return self._process_static_mode(request, context)

    def _process_static_mode(
        self, request: UIComponentRequest, context: ExecutionContext
    ) -> dict[str, Any]:
        """Process UI component in static mode with variable interpolation."""
        if self._is_widget_data_type(request.data_type):
            interpolated_data = self._process_widget_static_payload(request, context)
        else:
            interpolated_data = self.interpolator.interpolate_object(
                request.data, context.variables
            )

        return {
            "dataType": request.data_type.value,
            "data": interpolated_data,
        }

    async def _process_llm_mode(
        self, request: UIComponentRequest, context: ExecutionContext
    ) -> dict[str, Any]:
        """Process UI component in LLM mode with dynamic generation."""
        interpolated_input = self.interpolator.interpolate(
            request.input_data,
            context.variables,  # type: ignore
        )

        log.debug(
            "Generating UI component with LLM",
            data_type=request.data_type.value,
            input_length=len(interpolated_input),
        )

        # Configure LLM provider
        providers_config = {
            name: provider_config.credentials
            for name, provider_config in context.config.llm_providers.providers.items()
        }
        LLMProviderManager.configure("realtimexai", providers=providers_config)

        # Build LLM request
        llm_request = self._build_llm_request(request, interpolated_input)

        # Execute via LLMService
        response = await self.llm_service.complete(llm_request)

        return {
            "dataType": request.data_type.value,
            "data": self._format_llm_output(request, response.parsed_content),
        }

    def _build_llm_request(
        self,
        request: UIComponentRequest,
        input_prompt: str,
    ) -> LLMRequest:
        """Build LLMRequest for UI component generation."""
        system_prompt = (
            f"You are a UI data generator. Generate data for a {request.data_type.value} "
            "component that matches the provided JSON schema. Return only valid JSON that conforms "
            "to the schema structure. Do not include any explanations or additional text."
        )

        user_message = (
            f"Here is the input data to use for generating the UI component:\n\n{input_prompt}"
        )

        messages = self.llm_service.build_messages(user_message, system_prompt)

        schema = request.llm_schema
        json_schema_def = {
            "schema": schema,
            "name": f"{request.data_type.value}_component",
            "strict": False,
        }

        return LLMRequest(
            messages=messages,
            model="gpt-4o-mini",
            temperature=0.7,
            response_format={"type": "json_schema", "json_schema": json_schema_def},
        )

    def _format_llm_output(self, request: UIComponentRequest, generated_data: Any) -> Any:
        """Normalize LLM output across component types."""
        if self._is_widget_data_type(request.data_type):
            return self._build_widget_payload(request, generated_data)
        return generated_data

    def _build_widget_payload(
        self, request: UIComponentRequest, generated_data: Any
    ) -> dict[str, Any]:
        """Attach generated data to the widget payload while preserving configuration."""
        from copy import deepcopy

        content_template = request.widget_template
        if content_template is None:
            raise ExecutorError(
                "Widget components must define widget_template with widget metadata"
            )

        content_payload = deepcopy(content_template)
        content_payload["data"] = generated_data
        return {"content": content_payload}

    def _is_widget_data_type(self, data_type: UIComponentDataType) -> bool:
        """Check if the supplied UI data type represents a widget."""
        return data_type == UIComponentDataType.WIDGET

    def _process_widget_static_payload(
        self, request: UIComponentRequest, context: ExecutionContext
    ) -> dict[str, Any]:
        """Interpolate widget payload safely, preserving template metadata."""
        from copy import deepcopy

        content_template = request.widget_template
        if content_template is None:
            raise ExecutorError(
                "Widget components must define widget_template with widget metadata"
            )

        content_payload = deepcopy(content_template)
        data_section = content_payload.get("data")
        if data_section is None:
            raise ExecutorError("Widget components must provide data schema or payload")

        content_payload["data"] = self.interpolator.interpolate_object(
            data_section, context.variables
        )
        return {"content": content_payload}
