"""orc – board YAML CRUD operations.

All public functions delegate to the module-level :data:`_manager` singleton
(:class:`~orc.coordination.board._manager.FileBoardManager`).  Call
:func:`init_manager` once (done automatically by :func:`orc.config.init`).

.. note::

    The ``orc run`` dispatch loop does **not** use this module directly.
    It uses :class:`~orc.coordination.BoardStateManager`, which is the single
    thread-safe source of truth during a run.  This module is used by CLI
    read commands (``orc status``) and internal engine helpers.
"""

from __future__ import annotations

from pathlib import Path

import structlog

import orc.config as _cfg
from orc.coordination.board._manager import FileBoardManager, TaskStatus
from orc.coordination.models import Board, TaskBody, TaskEntry

logger = structlog.get_logger(__name__)

_manager: FileBoardManager | None = None


def init_manager() -> None:
    """Initialise (or reinitialise) the module-level BoardManager from Config."""
    global _manager
    _manager = FileBoardManager(_cfg.get().orc_dir)


def _get_manager() -> FileBoardManager:
    global _manager
    orc_dir = _cfg.get().orc_dir
    if _manager is None or _manager._work_dir != orc_dir / "work":
        _manager = FileBoardManager(orc_dir)
    return _manager


def _read_board() -> Board:
    return _get_manager().read_board()


def _write_board(board: Board) -> None:
    _get_manager().write_board(board)


def get_tasks() -> list[TaskEntry]:
    """Return the list of task entries from board.yaml."""
    return _read_board().tasks


def get_task(task_name: str) -> TaskEntry | None:
    """Return the board entry for *task_name*, or ``None`` if absent."""
    return _get_manager().get_task(task_name)


def set_task_status(task_name: str, status: str) -> None:
    """Set the ``status`` field of *task_name* in board.yaml."""
    _get_manager().set_task_status(task_name, status)


def add_task_comment(task_name: str, author: str, text: str) -> None:
    """Append a comment to *task_name*'s ``comments`` list."""
    _get_manager().add_task_comment(task_name, author, text)


def assign_task(task_name: str, agent_id: str) -> None:
    """Write ``assigned_to: {agent_id}`` for *task_name* and set status to ``in-progress``."""
    board = _read_board()
    for entry in board.tasks:
        if entry.name == task_name:
            entry.assigned_to = agent_id
            if entry.status in (None, "", TaskStatus.PLANNED):
                entry.status = TaskStatus.IN_PROGRESS
            _write_board(board)
            logger.debug("task assigned", task=task_name, agent_id=agent_id)
            return
    logger.warning("assign_task: task not found in board", task=task_name)


def unassign_task(task_name: str) -> None:
    """Clear the ``assigned_to`` field for *task_name* in board.yaml."""
    board = _read_board()
    changed = False
    for entry in board.tasks:
        if entry.name == task_name:
            entry.assigned_to = None
            changed = True
            break
    if changed:
        _write_board(board)
        logger.debug("task unassigned", task=task_name)


def clear_all_assignments() -> None:
    """Clear all ``assigned_to`` fields — called on startup for crash recovery."""
    board = _read_board()
    changed = False
    for entry in board.tasks:
        if entry.assigned_to is not None:
            entry.assigned_to = None
            changed = True
    if changed:
        _write_board(board)
        logger.info("cleared stale task assignments on startup")


def delete_task(task_name: str) -> None:
    """Remove *task_name* from board.yaml and delete its task file."""
    mgr = _get_manager()
    board = _read_board()
    board.tasks = [t for t in board.tasks if t.name != task_name]
    _write_board(board)
    mgr.delete_task_file(task_name)


def _read_work() -> str:
    """Return a human-readable kanban overview (board metadata only).

    Task file contents and comments are intentionally excluded so that
    agents stay focused.  Agents should use the ``share/get_task.py``
    tool to fetch a task's full details and conversation on demand.
    """
    mgr = _get_manager()
    board = mgr.read_board()

    task_lines: list[str] = []
    for t in board.tasks:
        task_lines.append(f"  - name: {t.name}")
        if t.status is not None:
            task_lines.append(f"    status: {t.status}")
        if t.assigned_to is not None:
            task_lines.append(f"    assigned_to: {t.assigned_to}")

    tasks_block = "\n".join(task_lines) if task_lines else "  []"
    body = f"counter: {board.counter}\ntasks:\n{tasks_block}"
    return f"### board.yaml\n\n```yaml\n{body}\n```"


def create_task(title: str, vision: str, body: TaskBody) -> tuple[str, Path]:
    """Create a task file and add a *planned* entry to board.yaml."""
    return _get_manager().create_task(title, vision, body)
