"""list_tags — return the user's tag vocabulary with usage counts.

Python-side aggregation rather than SQL UNNEST. Personal-scale (~thousands of
notes) makes the perf cost negligible, and a one-pass dict counter is much
easier to mock in tests than a GROUP BY-with-unnest expression.
"""
from __future__ import annotations

from sqlalchemy import select

from scribe.mcp._context import current_user_id
from scribe.models import async_session
from scribe.models.note import Note


def _aggregate_tag_counts(tag_lists) -> dict[str, int]:
    """Count occurrences across a sequence of (possibly-None) tag lists.

    Extracted so the aggregation logic can be unit-tested without a DB.
    """
    counts: dict[str, int] = {}
    for tags in tag_lists:
        for tag in (tags or []):
            counts[tag] = counts.get(tag, 0) + 1
    return counts


async def list_tags(limit: int = 50) -> dict:
    """Return the user's most-used tags with usage counts.

    Args:
        limit: Maximum number of tags to return (1-200).

    Returns:
        {"tags": [{"tag": "ops", "count": 12}, ...], "total": int}
        Sorted by count descending.
    """
    uid = current_user_id()
    limit = max(1, min(limit, 200))
    async with async_session() as session:
        result = await session.execute(
            select(Note.tags).where(Note.user_id == uid, Note.deleted_at.is_(None))
        )
        tag_lists = [row[0] for row in result.all()]
    counts = _aggregate_tag_counts(tag_lists)
    top = sorted(counts.items(), key=lambda x: x[1], reverse=True)[:limit]
    return {
        "tags": [{"tag": t, "count": c} for t, c in top],
        "total": len(top),
    }


def register(mcp) -> None:
    mcp.tool(name="list_tags")(list_tags)
