"""
全局分类树查询工具

从 MySQL global_tree_category 表读取分类层级，格式化为 [id]名称 的树形文本。
"""
from __future__ import annotations

import logging
from typing import Optional

from supply_agent.tools import tool
from supply_infra.db.models.global_tree_category import GlobalTreeCategory
from supply_infra.db.repositories.global_tree_category_repo import GlobalTreeCategoryRepository
from supply_infra.db.session import get_session

logger = logging.getLogger(__name__)

# 最末级（无子节点）标记
_LEAF_MARK = "*"


def _normalize_parent_id(parent_id: int | None) -> int | None:
    """将 0 或 None 统一视为根节点。"""
    if parent_id is None or parent_id == 0:
        return None
    return parent_id


def _build_children_map(
    categories: list[GlobalTreeCategory],
) -> dict[int | None, list[GlobalTreeCategory]]:
    children_map: dict[int | None, list[GlobalTreeCategory]] = {}
    for category in categories:
        parent_key = _normalize_parent_id(category.parent_id)
        children_map.setdefault(parent_key, []).append(category)

    for children in children_map.values():
        children.sort(key=lambda c: (c.level or 0, c.id))

    return children_map


def _format_category_tree(
    categories: list[GlobalTreeCategory],
    *,
    root_id: int | None = None,
    max_levels: int | None = None,
) -> str:
    """
    将分类列表格式化为层级分明的 [id]名称 树形文本。

    Args:
        categories: 全量分类列表
        root_id: 若指定，仅输出该节点及其子树（含自身）
        max_levels: 若指定，从起始节点算起最多输出多少层（含起始层）
    """
    if not categories:
        return "（暂无分类数据）"

    by_id = {category.id: category for category in categories}
    children_map = _build_children_map(categories)
    lines: list[str] = []

    def render(category: GlobalTreeCategory, depth: int, relative_level: int) -> None:
        if max_levels is not None and relative_level > max_levels:
            return

        indent = "  " * depth
        name = category.name or ""
        is_leaf = not children_map.get(category.id)
        leaf_suffix = f" {_LEAF_MARK}" if is_leaf else ""
        lines.append(f"{indent}[{category.id}]{name}{leaf_suffix}")

        if is_leaf or (max_levels is not None and relative_level >= max_levels):
            return

        for child in children_map.get(category.id, []):
            render(child, depth + 1, relative_level + 1)

    if root_id is not None:
        root = by_id.get(root_id)
        if root is None:
            return f"未找到 id={root_id} 的分类"
        render(root, 0, 1)
    else:
        for root in children_map.get(None, []):
            render(root, 0, 1)

    if not lines:
        return "（暂无分类数据）"
    return "\n".join(lines)


@tool
def query_global_tree_category(
    id: Optional[int] = None,
    level: Optional[int] = None,
) -> str:
    """
    查询全局分类树

    从 global_tree_category 表读取分类层级，返回格式化的树形文本。
    每行格式为 [id]名称，子级以两个空格缩进；最末级节点末尾带 * 标记。

    Args:
        id: 可选。不传查整棵树；传入则从该分类开始向下查询（含自身）。
        level: 可选。不传查到最底层；传入则只查从起始节点算起的指定层数（含起始层）。
              例如 id=1, level=3：输出 [1] 及其向下共 3 层。

    Returns:
        层级分明的分类树文本，例如：
        [1]表象
          [3]行为
            [19]表演 *
          [4]内容形态 *
        [2]理念 *
    """
    if level is not None and level < 1:
        return "level 必须大于等于 1"

    try:
        with get_session() as session:
            repo = GlobalTreeCategoryRepository(session)
            categories = repo.list_active_categories()
            tree_text = _format_category_tree(
                categories,
                root_id=id,
                max_levels=level,
            )

        logger.info(
            "query_global_tree_category completed: id=%s level=%s categories=%d",
            id,
            level,
            len(categories),
        )
        return tree_text

    except Exception as e:
        logger.error("query_global_tree_category failed: %s", e, exc_info=True)
        return f"查询全局分类树失败: {e}"
