"""Digital Employee Agent Builder.

This module provides the DigitalEmployeeAgentBuilder class for creating
DigitalEmployeeAgent instances with a fluent interface.

Authors:
    Immanuel Rhesa (immanuel.rhesa@gdplabs.id)

References:
    NONE
"""

from dataclasses import dataclass, field
from typing import Any, Self

from glaip_sdk import MCP, Agent, Tool
from gllm_pipeline.steps import ComponentStep, step

from digital_employee_core.constants import DEFAULT_MODEL_NAME
from digital_employee_core.constants.models import ensure_valid_model_name
from digital_employee_core.digital_employee.agent import DigitalEmployeeAgent
from digital_employee_core.digital_employee.builders.step_builder import StepBuilder
from digital_employee_core.digital_employee.config import DigitalEmployeeConfig
from digital_employee_core.escalation import EscalationConfig
from digital_employee_core.identity.identity import DigitalEmployeeIdentity
from digital_employee_core.schedule import ScheduleItemConfig


@dataclass
class DigitalEmployeeAgentBuilder(StepBuilder):
    """Builder for creating DigitalEmployeeAgent instances with a fluent interface.

    This builder provides a convenient way to construct a DigitalEmployeeAgent
    by chaining method calls. The identity (name, email, job) must be set from
    DigitalEmployeeBuilder via identity propagation.

    Attributes:
        _tools (list[Tool]): List of tools the agent can use.
        _sub_agents (list[Agent]): List of sub-agents.
        _mcps (list[MCP]): List of MCPs the agent can use.
        _configs (list[DigitalEmployeeConfig]): List of configuration objects.
        _model (str): Model identifier to use.
        _agent_config (dict[str, Any] | None): Agent execution configuration.
        _agent_coordinator_name (str | None): Name for agent coordinator.
        _schedules (list[ScheduleItemConfig]): List of schedule configurations for the agent.
        _escalation_config (EscalationConfig | None): Escalation configuration.

    Example:
        identity = DigitalEmployeeIdentity(
            name="Claudia",
            email="claudia@example.com",
            job=DigitalEmployeeJob(
                title="Digital Assistant",
                description="A helpful digital employee assistant",
                instruction=(
                    "You are a helpful digital employee assistant. When asked to send a welcome "
                    "email, craft a warm, professional message that introduces the team and includes "
                    "helpful resources. Do not ask for clarification, just proceed with sending the "
                    "email."
                ),
            ),
        )
        agent = (
            DigitalEmployeeAgentBuilder()
            .add_mcps([google_mail_mcp])
            .add_configs_from_env(["GOOGLE_MAIL_MCP_URL", "GOOGLE_MCP_X_API_KEY"])
            .build(identity=identity)
        )
    """

    _tools: list[Tool] = field(default_factory=list, init=False)
    _sub_agents: list[Agent] = field(default_factory=list, init=False)
    _mcps: list[MCP] = field(default_factory=list, init=False)
    _configs: list[DigitalEmployeeConfig] = field(default_factory=list, init=False)
    _model: str = field(default=DEFAULT_MODEL_NAME, init=False)
    _agent_config: dict[str, Any] | None = field(default=None, init=False)
    _agent_coordinator_name: str | None = field(default=None, init=False)
    _schedules: list[ScheduleItemConfig] = field(default_factory=list, init=False)
    _escalation_config: EscalationConfig = field(
        default_factory=lambda: EscalationConfig(enabled=False, channels=[]), init=False
    )

    def add_tools(self, tools: list[Tool]) -> Self:
        """Add tools to the digital employee.

        Args:
            tools (list[Tool]): List of tools the agent can use.

        Returns:
            Self: The builder instance for chaining.
        """
        self._tools.extend(tools)
        return self

    def add_sub_agents(self, sub_agents: list[Agent]) -> Self:
        """Add sub-agents to the digital employee.

        Args:
            sub_agents (list[Agent]): List of sub-agents.

        Returns:
            Self: The builder instance for chaining.
        """
        self._sub_agents.extend(sub_agents)
        return self

    def add_mcps(self, mcps: list[MCP]) -> Self:
        """Add MCPs to the digital employee.

        Args:
            mcps (list[MCP]): List of MCPs the agent can use.

        Returns:
            Self: The builder instance for chaining.
        """
        self._mcps.extend(mcps)
        return self

    def add_configs(self, configs: list[DigitalEmployeeConfig]) -> Self:
        """Add configurations to the digital employee.

        Args:
            configs (list[DigitalEmployeeConfig]): Configuration objects.

        Returns:
            Self: The builder instance for chaining.
        """
        self._configs.extend(configs)
        return self

    def add_configs_from_env(self, keys: list[str] | list[tuple[str, str]]) -> Self:
        """Add configurations from environment variables.

        Args:
            keys (list[str] | list[tuple[str, str]]): List of environment variable keys to load as configurations.
                Each item can be either:
                - A string key (uses empty string as default if not found)
                - A tuple of (key, default_value)

        Returns:
            Self: The builder instance for chaining.

        Examples:
            >>> builder.add_configs_from_env(["KEY1", "KEY2"])
            >>> builder.add_configs_from_env([("KEY1", "default1"), ("KEY2", "default2")])
            >>> builder.add_configs_from_env(["KEY1", ("KEY2", "default2")])
        """
        self._configs.extend(DigitalEmployeeConfig.from_env(*keys))
        return self

    def set_model(self, model: str) -> Self:
        """Set the model identifier.

        Args:
            model (str): Model identifier to use.

        Returns:
            Self: The builder instance for chaining.
        """
        self._model = ensure_valid_model_name(model)
        return self

    def set_agent_config(self, agent_config: dict[str, Any]) -> Self:
        """Set the agent configuration.

        Args:
            agent_config (dict[str, Any]): Agent execution configuration.

        Returns:
            Self: The builder instance for chaining.
        """
        self._agent_config = agent_config
        return self

    def set_agent_coordinator_name(self, name: str) -> Self:
        """Set the agent coordinator name.

        Args:
            name (str): Name for agent coordinator.

        Returns:
            Self: The builder instance for chaining.
        """
        self._agent_coordinator_name = name
        return self

    def add_schedules(self, schedules: list[ScheduleItemConfig]) -> Self:
        """Add schedule configurations.

        Args:
            schedules (list[ScheduleItemConfig]): List of schedule configurations for the agent.

        Returns:
            Self: The builder instance for chaining.
        """
        self._schedules.extend(schedules)
        return self

    def set_escalation_config(self, escalation_config: EscalationConfig) -> Self:
        """Set the escalation configuration.

        Args:
            escalation_config (EscalationConfig): Escalation configuration.

        Returns:
            Self: The builder instance for chaining.
        """
        self._escalation_config = escalation_config
        return self

    def build(self, identity: DigitalEmployeeIdentity) -> DigitalEmployeeAgent:
        """Build the DigitalEmployeeAgent instance.

        Args:
            identity (DigitalEmployeeIdentity): The identity for the agent.

        Returns:
            DigitalEmployeeAgent: The created Digital Employee Agent instance.
        """
        return DigitalEmployeeAgent(
            identity=identity,
            tools=self._tools,
            sub_agents=self._sub_agents,
            mcps=self._mcps,
            configurations=self._configs,
            model=self._model,
            agent_config=self._agent_config,
            agent_coordinator_name=self._agent_coordinator_name,
            schedules=self._schedules,
            escalation_config=self._escalation_config,
        )

    def build_step(
        self,
        identity: DigitalEmployeeIdentity,
        configs: list[DigitalEmployeeConfig] | None = None,
        **kwargs,
    ) -> ComponentStep:
        """Build a ComponentStep from this agent builder.

        This method creates a pipeline step that wraps the agent component.
        It accepts identity and configurations via kwargs to support the
        StepBuilder interface.

        Args:
            identity (DigitalEmployeeIdentity): The identity for the agent.
            configs (list[DigitalEmployeeConfig] | None):
                Optional configurations to add to the agent.
            **kwargs: Additional parameters (ignored).

        Returns:
            ComponentStep: The build pipeline step containing the agent.
        """
        if configs:
            self.add_configs(configs)

        agent = self.build(identity)
        agent_component = agent.get_agent_component()

        return step(
            component=agent_component,
            input_state_map={
                "query": "message",
                "runtime_config": "runtime_config",
                "run_kwargs": "run_kwargs",
            },
            output_state="agent_response",
        )
