"""System CRUD + record-association MCP tools — wrappers over services/systems.py.

A System is a per-project, reusable, self-describing subsystem/area that any
record (note, task, or issue) can be associated with — so research, build-work,
and corrective work line up under the same area and recurring problem-spots are
visible. The service enforces the multi-user ACL (project permission); these
tools are thin wrappers.

Sentinels (match the milestone/task tool conventions):
  - name="" / description="" / color="" / status="" → "leave unchanged" on update
  - order_index=-1 → "leave unchanged" on update (0 is a valid order_index)
"""
from __future__ import annotations

from scribe.mcp._context import current_user_id
from scribe.services import systems as systems_svc


async def create_system(
    project_id: int,
    name: str,
    description: str = "",
    color: str = "",
) -> dict:
    """Create a System (a reusable, self-describing subsystem/area) in a project.

    Associate records with it via the `system_ids` arg on create/update_task and
    create/update_note.

    Args:
        project_id: The project this system belongs to (required).
        name: Short label (required).
        description: What the system is and how it's used — a name is rarely enough.
        color: Optional UI accent (hex), or empty.
    """
    uid = current_user_id()
    system = await systems_svc.create_system(
        uid, project_id=project_id, name=name,
        description=description or None, color=color or None,
    )
    if system is None:
        raise ValueError(f"cannot create system in project {project_id} (no write access)")
    return system.to_dict()


async def list_systems(project_id: int, include_archived: bool = False) -> dict:
    """List a project's systems (active by default), ordered by order_index.

    Pass include_archived=True to include archived systems.
    """
    uid = current_user_id()
    rows = await systems_svc.list_systems(uid, project_id, include_archived=include_archived)
    return {"systems": [s.to_dict() for s in rows]}


async def get_system(system_id: int) -> dict:
    """Fetch a System plus the records associated with it.

    Returns the system, plus its associated records split into `issues`,
    `tasks` (work/plan), and `notes`.
    """
    uid = current_user_id()
    system = await systems_svc.get_system(uid, system_id)
    if system is None:
        raise ValueError(f"system {system_id} not found")
    records = await systems_svc.list_records_for_system(uid, system_id)
    issues, tasks, notes = [], [], []
    for r in records:
        d = r.to_dict()
        if r.status is None:
            notes.append(d)
        elif r.task_kind == "issue":
            issues.append(d)
        else:
            tasks.append(d)
    data = system.to_dict()
    data["issues"] = issues
    data["tasks"] = tasks
    data["notes"] = notes
    return data


async def update_system(
    system_id: int,
    name: str = "",
    description: str = "",
    color: str = "",
    status: str = "",
    order_index: int = -1,
) -> dict:
    """Update a System. Only explicitly provided fields change.

    Args:
        status: 'active' or 'archived'. Archive a system to retire it without
            losing history; archived systems hide from default lists.
        order_index: display position (0-based); -1 = leave unchanged.
    """
    uid = current_user_id()
    fields: dict = {}
    if name:
        fields["name"] = name
    if description:
        fields["description"] = description
    if color:
        fields["color"] = color
    if status:
        fields["status"] = status
    if order_index >= 0:
        fields["order_index"] = order_index
    system = await systems_svc.update_system(uid, system_id, **fields)
    if system is None:
        raise ValueError(f"system {system_id} not found or no write access")
    return system.to_dict()


async def list_system_records(
    system_id: int, kind: str = "", open_only: bool = False
) -> dict:
    """Everything filed under one System — the way to READ a subsystem.

    Reach for this when investigating a specific area: it returns the notes,
    tasks, issues and snippets someone deliberately tagged to it — the
    subsystem's accumulated record, unranked. Start with its reference note if
    one exists (titled "«System» — reference"); that is the living state, and
    the rest is history and open work around it. For a ranked cut of the same
    slice, search(system_id=...) filters semantic search to this association.

    Args:
        kind: filter by task_kind — 'issue', 'work', or 'plan'. Omit for all.
        open_only: limit to tasks not done/cancelled (e.g. open issues only).
    """
    uid = current_user_id()
    rows = await systems_svc.list_records_for_system(
        uid, system_id, kind=kind or None, open_only=open_only,
    )
    return {"records": [r.to_dict() for r in rows]}


async def delete_system(system_id: int) -> dict:
    """Soft-delete a System (recoverable). Its record associations are removed."""
    uid = current_user_id()
    ok = await systems_svc.delete_system(uid, system_id)
    if not ok:
        raise ValueError(f"system {system_id} not found or no write access")
    return {"message": f"System {system_id} deleted."}


def register(mcp) -> None:
    for fn in (
        create_system,
        list_systems,
        get_system,
        update_system,
        list_system_records,
        delete_system,
    ):
        mcp.tool(name=fn.__name__)(fn)
