"""Task executor - connects the Kanban TUI to the EmDash agent via SSE."""

import asyncio
import json
from typing import AsyncIterator, Callable

import httpx

from .models import Task, ColumnId, AIStatus


def create_task_executor(
    model: str = "claude-sonnet-4",
    max_iterations: int = 100,
) -> Callable[[Task], AsyncIterator[dict]]:
    """Create an async executor for Kanban tasks.

    Args:
        model: Model name to use
        max_iterations: Maximum agent iterations

    Returns:
        Async callable that takes a Task and yields events
    """
    # Get server URL from server manager
    from ...server_manager import get_server_manager

    server = get_server_manager()
    server_url = server.get_server_url()

    async def execute(task: Task) -> AsyncIterator[dict]:
        """Execute a task through the AI agent.

        The execution goes through two phases:
        1. Planning: Generate a plan for the task
        2. Implementation: Execute the plan

        Args:
            task: The task to execute

        Yields:
            Event dicts with type and data keys
        """
        async with httpx.AsyncClient(timeout=None) as client:
            # Phase 1: Planning
            plan_prompt = f"""You are working on a task from a Kanban board.

Task: {task.title}
Description: {task.description}

Please analyze this task and create a plan. The plan should:
1. Break down the work into clear steps
2. Identify files that need to be modified
3. Consider any edge cases or dependencies

After planning, implement the changes."""

            payload = {
                "message": plan_prompt,
                "model": model,
                "options": {
                    "max_iterations": max_iterations,
                    "verbose": True,
                    "mode": "code",  # Use code mode for full implementation
                },
            }

            url = f"{server_url}/api/agent/chat"

            try:
                plan_content = []
                implementation_started = False

                async with client.stream("POST", url, json=payload) as response:
                    response.raise_for_status()

                    current_event = None

                    async for line in response.aiter_lines():
                        line = line.strip()

                        if line.startswith("event: "):
                            current_event = line[7:]
                        elif line.startswith("data: "):
                            if current_event:
                                try:
                                    data = json.loads(line[6:])
                                    if data is None:
                                        data = {}

                                    # Transform events for Kanban UI
                                    if current_event == "thinking":
                                        content = data.get("content", "")
                                        if content:
                                            plan_content.append(content)
                                        yield {
                                            "type": "thinking",
                                            "data": {"content": content},
                                        }

                                    elif current_event == "tool_start":
                                        # First tool use means planning is done
                                        if not implementation_started:
                                            implementation_started = True
                                            yield {
                                                "type": "plan_complete",
                                                "data": {"plan": "\n".join(plan_content[:5])},
                                            }
                                        yield {
                                            "type": "tool_start",
                                            "data": data,
                                        }

                                    elif current_event == "tool_result":
                                        yield {
                                            "type": "tool_result",
                                            "data": data,
                                        }

                                    elif current_event == "response":
                                        yield {
                                            "type": "response",
                                            "data": data,
                                        }

                                    elif current_event == "error":
                                        yield {
                                            "type": "error",
                                            "data": data,
                                        }

                                    elif current_event in ("subagent_start", "subagent_end"):
                                        yield {
                                            "type": current_event,
                                            "data": data,
                                        }

                                except json.JSONDecodeError:
                                    pass
                        elif line == ": ping":
                            # Keep-alive ping - ignore
                            pass

            except httpx.HTTPError as e:
                yield {
                    "type": "error",
                    "data": {"message": f"HTTP error: {str(e)}"},
                }
            except Exception as e:
                yield {
                    "type": "error",
                    "data": {"message": str(e)},
                }

    return execute


class TaskExecutorManager:
    """Manages parallel execution of multiple tasks."""

    def __init__(
        self,
        executor: Callable[[Task], AsyncIterator[dict]],
        max_concurrent: int = 2,
    ):
        """Initialize the executor manager.

        Args:
            executor: The task executor callable
            max_concurrent: Maximum number of concurrent tasks
        """
        self.executor = executor
        self.max_concurrent = max_concurrent
        self._running: dict[str, asyncio.Task] = {}
        self._semaphore = asyncio.Semaphore(max_concurrent)

    async def start_task(
        self,
        task: Task,
        on_event: Callable[[str, dict], None],
    ) -> None:
        """Start executing a task.

        Args:
            task: The task to execute
            on_event: Callback for task events
        """
        if task.id in self._running:
            return  # Already running

        async def run():
            async with self._semaphore:
                try:
                    async for event in self.executor(task):
                        on_event(task.id, event)
                except asyncio.CancelledError:
                    on_event(task.id, {
                        "type": "cancelled",
                        "data": {"message": "Task cancelled"},
                    })
                except Exception as e:
                    on_event(task.id, {
                        "type": "error",
                        "data": {"message": str(e)},
                    })
                finally:
                    if task.id in self._running:
                        del self._running[task.id]

        self._running[task.id] = asyncio.create_task(run())

    def cancel_task(self, task_id: str) -> bool:
        """Cancel a running task.

        Args:
            task_id: ID of the task to cancel

        Returns:
            True if task was cancelled, False if not running
        """
        if task_id in self._running:
            self._running[task_id].cancel()
            return True
        return False

    def cancel_all(self) -> None:
        """Cancel all running tasks."""
        for task_future in self._running.values():
            task_future.cancel()

    @property
    def running_count(self) -> int:
        """Number of currently running tasks."""
        return len(self._running)

    @property
    def can_start_more(self) -> bool:
        """Whether we can start more tasks."""
        return len(self._running) < self.max_concurrent
