from __future__ import annotations

import json
from typing import Any

try:
    from . import route_metadata as route_metadata_policy
except ImportError:  # Allows local smoke tests with top-level imports.
    import route_metadata as route_metadata_policy


PAIR_SIDES = ("softcore", "hardcore")


def route_trace_json(**values: Any) -> str:
    trace: dict[str, Any] = {}
    for key, value in values.items():
        if value is None:
            continue
        if isinstance(value, str):
            value = value.strip()
            if not value:
                continue
        trace[key] = value
    return json.dumps(trace, ensure_ascii=True, sort_keys=True)


def _pair_selected_side(target: Any, selected_side: Any = "") -> str:
    side = str(selected_side or "").strip().lower()
    if side in PAIR_SIDES:
        return side
    target_side = str(target or "").strip().lower()
    return target_side if target_side in PAIR_SIDES else "softcore"


def _add_if_value(trace: dict[str, Any], key: str, value: Any) -> None:
    if value is None:
        return
    if isinstance(value, str):
        value = value.strip()
        if not value:
            return
    if isinstance(value, (list, tuple, set)) and not value:
        return
    trace[key] = value


def metadata_trace_fields(row: Any, *, target: Any = "", selected_side: Any = "") -> dict[str, Any]:
    """Return compact row metadata fields for formatter route traces.

    The trace intentionally carries routing/debug identifiers, not full prompt
    prose or cast descriptors.
    """
    if not isinstance(row, dict):
        return {}
    trace: dict[str, Any] = {}
    source_row = row
    if isinstance(row.get("softcore_row"), dict) or isinstance(row.get("hardcore_row"), dict):
        side = _pair_selected_side(target, selected_side)
        source_row = row.get(f"{side}_row") if isinstance(row.get(f"{side}_row"), dict) else {}
        trace["metadata_kind"] = "pair"
        trace["selected_side"] = side
    else:
        trace["metadata_kind"] = "row"

    if not isinstance(source_row, dict):
        return trace

    _add_if_value(trace, "metadata_category", source_row.get("main_category") or source_row.get("category"))
    _add_if_value(trace, "metadata_subcategory", source_row.get("subcategory"))
    _add_if_value(trace, "action_family", route_metadata_policy.row_action_family(source_row))
    _add_if_value(trace, "position_family", route_metadata_policy.row_position_family(source_row))
    _add_if_value(trace, "position_key", source_row.get("position_key"))
    _add_if_value(trace, "position_keys", route_metadata_policy.row_position_keys(source_row, include_unknown=True))
    _add_if_value(trace, "scene_profile", source_row.get("scene_camera_profile_key"))
    _add_if_value(trace, "pov_labels", source_row.get("pov_character_labels"))
    return trace
