"""Main Agent class — orchestrates the ReAct loop and task lifecycle."""

from __future__ import annotations

import asyncio
import time

from agent_scout.db.models import AutonomyLevel, Task, TaskStatus
from agent_scout.events import Event, EventBus, EventType
from agent_scout.react_loop import (
    ActionType,
    LLMProvider,
    ReActConfig,
    ReActLoop,
    ToolExecutor,
    UserInteraction,
)


class Agent:
    """The main AgentScout agent.

    Accepts natural language tasks, manages the ReAct loop lifecycle,
    handles autonomy levels, and emits structured events for live UI updates.
    """

    def __init__(
        self,
        llm: LLMProvider,
        tools: ToolExecutor,
        event_bus: EventBus,
        user: UserInteraction | None = None,
        autonomy: AutonomyLevel = AutonomyLevel.FULL,
        max_iterations: int = 25,
    ) -> None:
        self._llm = llm
        self._tools = tools
        self._bus = event_bus
        self._user = user
        self._autonomy = autonomy
        self._max_iterations = max_iterations
        self._active_loops: dict[str, ReActLoop] = {}
        self._lock = asyncio.Lock()

    @property
    def autonomy(self) -> AutonomyLevel:
        return self._autonomy

    @autonomy.setter
    def autonomy(self, level: AutonomyLevel) -> None:
        self._autonomy = level

    async def run_task(self, task: Task) -> Task:
        """Execute a task through the ReAct loop.

        Updates the task status through its lifecycle and returns
        the completed/failed task.
        """
        task.status = TaskStatus.PLANNING
        task.updated_at = time.time()
        await self._bus.emit(
            Event(
                event_type=EventType.TASK_STATE_CHANGE,
                data={"status": task.status.value, "description": task.description},
                task_id=task.id,
            )
        )

        await self._bus.emit(
            Event(
                event_type=EventType.AGENT_STARTED,
                data={
                    "task_id": task.id,
                    "description": task.description,
                    "autonomy": self._autonomy.value,
                },
                task_id=task.id,
            )
        )

        # Determine effective user interaction based on autonomy
        effective_user = self._get_effective_user(task)

        config = ReActConfig(
            max_iterations=self._max_iterations,
            enable_reflection=True,
        )

        loop = ReActLoop(
            llm=self._llm,
            tools=self._tools,
            event_bus=self._bus,
            user=effective_user,
            config=config,
        )

        async with self._lock:
            self._active_loops[task.id] = loop

        try:
            task.status = TaskStatus.EXECUTING
            task.updated_at = time.time()
            await self._bus.emit(
                Event(
                    event_type=EventType.TASK_STATE_CHANGE,
                    data={"status": task.status.value},
                    task_id=task.id,
                )
            )

            steps = await loop.run(task.description, task_id=task.id)

            # Determine outcome from final step
            if steps and steps[-1].action.action_type == ActionType.FINISH:
                task.status = TaskStatus.COMPLETED
                task.result = steps[-1].action.result or {"message": steps[-1].action.message}
            else:
                task.status = TaskStatus.FAILED
                task.error = "Max iterations reached without completion"

        except Exception as e:
            task.status = TaskStatus.FAILED
            task.error = str(e)
            await self._bus.emit(
                Event(
                    event_type=EventType.ERROR,
                    data={"error": str(e)},
                    task_id=task.id,
                )
            )

        finally:
            async with self._lock:
                self._active_loops.pop(task.id, None)

            task.updated_at = time.time()
            event_type = (
                EventType.TASK_COMPLETED
                if task.status == TaskStatus.COMPLETED
                else EventType.TASK_FAILED
            )
            await self._bus.emit(
                Event(
                    event_type=event_type,
                    data={
                        "status": task.status.value,
                        "result": task.result,
                        "error": task.error,
                    },
                    task_id=task.id,
                )
            )

            await self._bus.emit(
                Event(
                    event_type=EventType.AGENT_STOPPED,
                    data={"task_id": task.id},
                    task_id=task.id,
                )
            )

        return task

    def _get_effective_user(self, task: Task) -> UserInteraction | None:
        """Determine the user interaction handler based on autonomy level."""
        effective_autonomy = task.autonomy if task.autonomy else self._autonomy

        if effective_autonomy == AutonomyLevel.FULL:
            # In full autonomy, agent doesn't ask user (unless task explicitly requires it)
            return None
        # Semi and step_by_step both allow user interaction
        return self._user

    async def stop_task(self, task_id: str) -> None:
        """Stop a running task."""
        async with self._lock:
            loop = self._active_loops.get(task_id)
        if loop:
            loop.stop()

    @property
    def active_task_ids(self) -> list[str]:
        return list(self._active_loops.keys())
