"""Escalation manager for Digital Employee.

This module provides the EscalationManager class that handles escalation
channel management, prompt building, and dependency collection.

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

References:
    NONE
"""

from glaip_sdk import MCP, Tool
from gllm_core.utils import LoggerManager

from digital_employee_core.digital_employee.dependencies import DependencyBundle
from digital_employee_core.escalation.base_escalation_channel import EscalationChannel
from digital_employee_core.escalation.config import EscalationConfig
from digital_employee_core.escalation.constant import (
    ESCALATION_PROMPT,
)
from digital_employee_core.identity.identity import DigitalEmployeeSupervisor

logger = LoggerManager().get_logger(__name__)


class EscalationManager:
    """Manages escalation channels and escalation-related operations.

    This class handles escalation channel management, prompt building,
    and dependency (tools/MCPs) collection for escalation functionality.

    Attributes:
        config (EscalationConfig): The escalation configuration.
        supervisor (DigitalEmployeeSupervisor | None): The supervisor to escalate to.
    """

    def __init__(self, config: EscalationConfig, supervisor: DigitalEmployeeSupervisor | None) -> None:
        """Initialize the EscalationManager.

        Args:
            config (EscalationConfig): The escalation configuration.
            supervisor (DigitalEmployeeSupervisor | None): The supervisor to escalate to.
        """
        self.config = config
        self.supervisor = supervisor

    @property
    def is_active(self) -> bool:
        """Check if escalation is currently active.

        Returns:
            bool: True if escalation is enabled, a supervisor is set, and channels are configured.
        """
        return bool(self.config.enabled and self.supervisor and self.config.channels)

    def enable(self) -> None:
        """Enable escalation for the agent."""
        self.config.enabled = True

    def disable(self) -> None:
        """Disable escalation for the agent."""
        self.config.enabled = False

    def add_channel(self, channel: EscalationChannel) -> None:
        """Add an escalation channel to the agent.

        Args:
            channel (EscalationChannel): The escalation channel to add.
        """
        if channel not in self.config.channels:
            self.config.channels.append(channel)

    def remove_channel(self, channel: EscalationChannel) -> None:
        """Remove an escalation channel from the agent.

        Args:
            channel (EscalationChannel): The escalation channel to remove.
        """
        if channel in self.config.channels:
            self.config.channels.remove(channel)

    def inject_into_prompt(self, prompt: str) -> str:
        """Inject the escalation protocol section into the prompt.

        Args:
            prompt (str): The original prompt.

        Returns:
            str: The prompt with the escalation protocol section injected if active.
        """
        if not self.is_active:
            return prompt

        new_prompt = f"{prompt}\n\n{self._build_prompt_section()}"
        return new_prompt

    def get_dependencies(self) -> tuple[list[Tool], list[MCP]]:
        """Build tools and MCPs required by escalation channels.

        Returns:
            tuple[list[Tool], list[MCP]]: Tuple containing the required tools and MCPs.
        """
        if not self.is_active:
            return [], []

        required_mcps = DependencyBundle.dedupe_preserve_order(
            [mcp for channel in self.config.channels for mcp in channel.get_required_mcps()]
        )
        required_tools = DependencyBundle.dedupe_preserve_order(
            [tool for channel in self.config.channels for tool in channel.get_required_tools()]
        )

        return required_tools, required_mcps

    def _build_prompt_section(self) -> str:
        """Build the escalation protocol section of the prompt.

        Returns:
            str: The escalation protocol instructions.
        """
        escalation_prompt_lines = [ESCALATION_PROMPT]

        for channel in self.config.channels:
            escalation_prompt_lines.append(channel.get_prompt_instruction(self.supervisor))

        return "\n".join(escalation_prompt_lines).strip()
