"""Execution phase for deliberate."""

import time
import uuid
from dataclasses import dataclass
from pathlib import Path

from deliberate.adapters.base import ModelAdapter
from deliberate.budget.tracker import BudgetTracker
from deliberate.git.worktree import Worktree, WorktreeManager
from deliberate.prompts.execution import (
    EXECUTION_NO_PLAN,
    EXECUTION_PROMPT,
    EXECUTION_WITH_PLAN,
)
from deliberate.types import ExecutionResult, Plan


async def execute_single_agent(
    agent: ModelAdapter,
    task: str,
    worktree_path: str | None = None,
    budget_tracker: BudgetTracker | None = None,
    phase: str = "execution",
    worktree_mgr: WorktreeManager | None = None,
    timeout_seconds: int = 1200,
) -> ExecutionResult:
    """Execute single agent, optionally in existing worktree.

    Args:
        agent: The model adapter to use.
        task: The task description/prompt.
        worktree_path: Optional existing worktree path to reuse.
        budget_tracker: Optional budget tracker for recording usage.
        phase: Workflow phase name for budget tracking.
        worktree_mgr: Worktree manager for creating/managing worktrees.
        timeout_seconds: Timeout for agent execution.

    Returns:
        ExecutionResult with outcome of execution.
    """
    start = time.time()
    result_id = f"exec-{uuid.uuid4().hex[:8]}"

    worktree: Worktree | None = None
    working_dir: Path

    try:
        # Determine working directory
        if worktree_path:
            # Reuse existing worktree
            working_dir = Path(worktree_path)
        elif worktree_mgr:
            # Create new worktree
            worktree = worktree_mgr.create(name=result_id)
            working_dir = worktree.path
        else:
            # Use current directory (no worktree)
            working_dir = Path.cwd()

        # Execute the task
        response = await agent.run_agentic(
            task=task,
            working_dir=str(working_dir),
            timeout_seconds=timeout_seconds,
        )

        # Record budget usage with phase tracking
        if budget_tracker:
            budget_tracker.record_usage(
                agent.name,
                response.token_usage,
                agent.estimate_cost(response.token_usage),
                phase=phase,
            )

        # Get the diff if using worktrees
        diff = None
        if worktree_mgr and (worktree or worktree_path):
            # For reused worktrees, create temp Worktree object for diff extraction
            if worktree_path and not worktree:
                worktree = Worktree(name=Path(worktree_path).name, path=Path(worktree_path))
            diff = worktree_mgr.get_diff(worktree)

        return ExecutionResult(
            id=result_id,
            agent=agent.name,
            worktree_path=working_dir,
            diff=diff,
            summary=response.content,
            success=True,
            duration_seconds=time.time() - start,
            token_usage=response.token_usage,
        )

    except Exception as e:
        return ExecutionResult(
            id=result_id,
            agent=agent.name,
            worktree_path=working_dir if 'working_dir' in locals() else None,
            diff=None,
            summary="",
            success=False,
            error=str(e),
            duration_seconds=time.time() - start,
        )


@dataclass
class ExecutionPhase:
    """Orchestrates the execution phase of the jury workflow.

    Agents execute the task (with optional plan) in isolated
    git worktrees, producing diffs and summaries.
    """

    agents: list[str]
    adapters: dict[str, ModelAdapter]
    budget: BudgetTracker
    worktree_mgr: WorktreeManager
    use_worktrees: bool = True
    timeout_seconds: int = 1200

    async def run(
        self,
        task: str,
        plan: Plan | None = None,
    ) -> list[ExecutionResult]:
        """Run the execution phase.

        Args:
            task: The task description.
            plan: Optional plan to follow.

        Returns:
            List of execution results from all agents.
        """
        results = []
        for agent_name in self.agents:
            result = await self._execute_single(agent_name, task, plan)
            results.append(result)
        return results

    async def _execute_single(
        self,
        agent_name: str,
        task: str,
        plan: Plan | None,
    ) -> ExecutionResult:
        """Execute the task with a single agent."""
        adapter = self.adapters.get(agent_name)
        if not adapter:
            return ExecutionResult(
                id=f"exec-{uuid.uuid4().hex[:8]}",
                agent=agent_name,
                worktree_path=None,
                diff=None,
                summary="",
                success=False,
                error="Adapter not found",
                duration_seconds=0.0,
            )

        # Build the prompt
        if plan:
            plan_section = EXECUTION_WITH_PLAN.format(plan=plan.content)
        else:
            plan_section = EXECUTION_NO_PLAN

        prompt = EXECUTION_PROMPT.format(
            task=task,
            plan_section=plan_section,
            working_dir="<will be set by executor>",
        )

        # Use standalone function with phase tracking
        return await execute_single_agent(
            agent=adapter,
            task=prompt,
            worktree_path=None,  # Create new worktree
            budget_tracker=self.budget,
            phase="execution",
            worktree_mgr=self.worktree_mgr if self.use_worktrees else None,
            timeout_seconds=self.timeout_seconds,
        )
