"""Core digital employee orchestrator.

This module provides the base DigitalEmployee class that manages pipelines
and schedules. The agent functionality has been separated to DigitalEmployeeAgent.

Authors:
    Immanuel Rhesa (immanuel.rhesa@gdplabs.id)
    Vio Albert Ferdinand (vio.a.ferdinand@gdplabs.id)

References:
    NONE
"""

from dataclasses import dataclass, field
from typing import Any

from gllm_core.utils import LoggerManager
from gllm_pipeline.pipeline.pipeline import Pipeline
from gllm_pipeline.steps import ComponentStep

from digital_employee_core.digital_employee.config import DigitalEmployeeConfig
from digital_employee_core.digital_employee.state import DigitalEmployeeState
from digital_employee_core.identity.identity import DigitalEmployeeIdentity

logger = LoggerManager().get_logger(__name__)


@dataclass
class DigitalEmployee:
    """Core digital employee orchestrator with pipeline-based execution.

    This class manages the lifecycle of a digital employee with a focus on
    pipeline execution. The agent functionality has been separated to
    DigitalEmployeeAgent, and the agent is now an optional component that
    can be added to the pipeline.

    Attributes:
        identity (DigitalEmployeeIdentity): The digital employee's identity.
        pipeline (Pipeline): The main pipeline instance that orchestrates execution.
        configs (list[DigitalEmployeeConfig]): List of configuration objects.
    """

    identity: DigitalEmployeeIdentity
    pipeline: Pipeline
    configs: list[DigitalEmployeeConfig] = field(default_factory=list)

    def clear_pipeline_steps(self) -> None:
        """Clear all pipeline steps."""
        self.pipeline.steps = []

    def add_pipeline_step(self, step: ComponentStep) -> None:
        """Add a pipeline step.

        Args:
            step (ComponentStep): The pipeline step to append.
        """
        self.pipeline.steps.append(step)

    def remove_pipeline_step(self, step: ComponentStep) -> None:
        """Remove a pipeline step.

        Args:
            step (ComponentStep): The pipeline step to remove.
        """
        if step in self.pipeline.steps:
            self.pipeline.steps.remove(step)

    def get_pipeline_steps(self) -> list[ComponentStep]:
        """Get all pipeline steps.

        Returns:
            list[ComponentStep]: List of pipeline steps.
        """
        return self.pipeline.steps

    # TODO: Add support to pass inital state from outside so not limited to DigitalEmployeeState only
    async def invoke(self, message: str, local: bool = True, **kwargs: Any) -> dict:
        """Run the digital employee with a message asynchronously using the pipeline.

        This method uses the pipeline infrastructure to execute the digital employee.

        Args:
            message (str): The message/prompt to send to digital employee.
            local (bool): Whether to run locally. Defaults to True.
            **kwargs (Any): Additional keyword arguments to pass to the pipeline.
                These will be passed as run_kwargs to the agent (e.g., verbose, temperature, etc.).

        Returns:
            dict: The final response from the pipeline.

        Raises:
            RuntimeError: If the pipeline is not configured or pipeline execution fails.
        """
        initial_state: DigitalEmployeeState = {
            "message": message,
            "agent_response": "",
            "runtime_config": None,
            "run_kwargs": {"local": local, **kwargs},
        }

        try:
            result = await self.pipeline.invoke(initial_state)
        except Exception as e:
            logger.error(f"Pipeline invocation failed for {self.identity.name}: {e}")
            raise RuntimeError(f"Digital employee {self.identity.name} failed: {e}") from e

        return result
