"""按需求数量自动划分分级计划组（替代统筹 Agent 的默认定时任务路径）。"""
from __future__ import annotations

import logging
from typing import Any

from agents.demand_grade_orchestrator_agent.common.assignment import (
    resolve_planning_state,
)
from agents.demand_grade_orchestrator_agent.common.plan_persist import persist_groups_one_by_one
from agents.demand_grade_orchestrator_agent.common.plan_record import prepare_grade_groups
from agents.demand_grade_orchestrator_agent.common.tree_state import load_tree_state
from supply_infra.scheduler.plan_group_batch import (
    MAX_DEMANDS_PER_BATCH,
    pack_category_units,
    resolve_demands_for_category_ids,
)

logger = logging.getLogger(__name__)

_DEFAULT_GROUPING_STRATEGY = "同分类与同父分类优先，每组约30个需求"
_DEFAULT_REASON = "代码自动分配"
_DEFAULT_TRAITS = _DEFAULT_GROUPING_STRATEGY


def _parent_id(category_id: int, by_id: dict[int, Any]) -> int | None:
    row = by_id.get(category_id)
    if row is None:
        return None
    parent = getattr(row, "parent_id", None)
    if parent in (None, 0):
        return None
    return int(parent)


def build_auto_assign_groups(
    biz_dt: str,
    *,
    unassigned_category_ids: list[int] | None = None,
    max_demands_per_group: int = MAX_DEMANDS_PER_BATCH,
) -> list[dict[str, Any]]:
    """为未分批分类节点生成自动分配批次（仅 category_ids，供 prepare_grade_groups 使用）。"""
    planning_state = resolve_planning_state(biz_dt)
    category_ids = list(unassigned_category_ids or planning_state["unassigned_category_ids"])
    if not category_ids:
        return []

    by_id, _children, _weights = load_tree_state(biz_dt)
    units: list[tuple[int, int | None, list[dict[str, Any]]]] = []
    for category_id in category_ids:
        demands = resolve_demands_for_category_ids(biz_dt, [category_id])
        if not demands:
            continue
        units.append((category_id, _parent_id(category_id, by_id), demands))

    packed = pack_category_units(units, max_demands_per_group=max_demands_per_group)
    return [
        {
            "category_ids": group_category_ids,
            "planning_reason": _DEFAULT_REASON,
            "shared_traits": _DEFAULT_TRAITS,
        }
        for group_category_ids in packed
    ]


def auto_assign_daily_grade_plan(
    *,
    biz_dt: str,
    max_demands_per_group: int = MAX_DEMANDS_PER_BATCH,
) -> dict[str, Any]:
    """自动划分并落库当天分级计划组（每组约 30 个需求，同分类/同父分类优先）。"""
    planning_state = resolve_planning_state(biz_dt)
    if not planning_state["can_plan_more"]:
        logger.info(
            "跳过自动分配: biz_dt=%s reason=%s",
            biz_dt,
            planning_state["skip_reason"],
        )
        return {
            "skipped": True,
            "reason": planning_state["skip_reason"],
            "planning_state": planning_state,
        }

    groups = build_auto_assign_groups(
        biz_dt,
        unassigned_category_ids=planning_state["unassigned_category_ids"],
        max_demands_per_group=max_demands_per_group,
    )
    if not groups:
        logger.info(
            "跳过自动分配：无待分配需求 biz_dt=%s unassigned_categories=%s",
            biz_dt,
            len(planning_state["unassigned_category_ids"]),
        )
        return {
            "skipped": True,
            "reason": "无待分配需求",
            "planning_state": planning_state,
        }

    logger.info(
        "执行自动分配: biz_dt=%s unassigned_categories=%s planned_groups=%s max_demands_per_group=%s",
        biz_dt,
        len(planning_state["unassigned_category_ids"]),
        len(groups),
        max_demands_per_group,
    )

    prepared = prepare_grade_groups(
        biz_dt,
        _DEFAULT_GROUPING_STRATEGY,
        groups,
        assigned_category_ids=set(planning_state["assigned_category_ids"]),
    )
    persist_result = persist_groups_one_by_one(biz_dt, prepared)
    return {
        "skipped": False,
        "planning_state": planning_state,
        "prepared_group_count": len(prepared.get("groups") or []),
        "persist_result": persist_result,
    }
