"""Output assembly helpers for benchmark case evaluation."""

from __future__ import annotations

from typing import Any


def _as_dict(value: Any) -> dict[str, Any]:
    return value if isinstance(value, dict) else {}


def build_case_detail_payload(
    *,
    top_candidates: list[Any],
    included_candidate_paths: list[str],
    included_candidate_globs: list[str],
    excluded_candidate_paths: list[str],
    excluded_candidate_globs: list[str],
    relevant_candidate_paths: list[str],
    noise_candidate_paths: list[str],
    candidate_matches: list[dict[str, Any]],
    top_chunks: list[Any],
    expected_hits: list[str],
    chunk_hits: list[str],
    validation_tests: list[Any],
    source_plan_evidence_summary: dict[str, float],
    source_plan_card_summary: dict[str, Any],
    source_plan_failure_signal_summary: dict[str, Any],
    memory_latency_ms: float,
    index_latency_ms: float,
    repomap_latency_ms: float,
    repomap_worktree_seed_count: int,
    repomap_subgraph_seed_count: int,
    repomap_seed_candidates_count: int,
    repomap_cache_hit: bool,
    repomap_precompute_hit: bool,
    augment_latency_ms: float,
    skills_latency_ms: float,
    source_plan_latency_ms: float,
    retrieval_context_chunk_count: int,
    retrieval_context_coverage_ratio: float,
    retrieval_context_char_count_mean: float,
    contextual_sidecar_parent_symbol_chunk_count: int,
    contextual_sidecar_parent_symbol_coverage_ratio: float,
    contextual_sidecar_reference_hint_chunk_count: int,
    contextual_sidecar_reference_hint_coverage_ratio: float,
    chunk_contract_fallback_count: int,
    chunk_contract_skeleton_chunk_count: int,
    chunk_contract_fallback_ratio: float,
    chunk_contract_skeleton_ratio: float,
    chunk_cache_contract_present: bool,
    chunk_cache_contract_fingerprint_present: bool,
    chunk_cache_contract_metadata_aligned: bool,
    chunk_cache_contract_file_count: int,
    chunk_cache_contract_chunk_count: int,
    unsupported_language_fallback_count: int,
    unsupported_language_fallback_ratio: float,
    subgraph_payload_enabled: bool,
    subgraph_payload: dict[str, Any],
    subgraph_seed_path_count: int,
    subgraph_edge_type_count: int,
    subgraph_edge_total_count: int,
    subgraph_seed_paths: list[str],
    subgraph_edge_counts: dict[str, Any],
    skills_selected_count: int,
    skills_token_budget: float,
    skills_token_budget_used: float,
    skills_token_budget_utilization_ratio: float,
    skills_budget_exhausted: bool,
    skills_skipped_for_budget_count: int,
    skills_payload: dict[str, Any],
    skills_metadata_only_routing: bool,
    skills_route_latency_ms: float,
    skills_hydration_latency_ms: float,
    plan_replay_cache_enabled: bool,
    plan_replay_cache_hit: bool,
    plan_replay_cache_stale_hit_safe: bool,
    plan_replay_cache_payload: dict[str, Any],
    chunk_stage_miss: dict[str, Any],
    slo_downgrade_signals: list[str],
    parallel_time_budget_ms: float,
    embedding_time_budget_ms: float,
    chunk_semantic_time_budget_ms: float,
    xref_time_budget_ms: float,
    chunk_guard_mode: str,
    chunk_guard_reason: str,
    chunk_guard_candidate_pool: int,
    chunk_guard_signed_chunk_count: int,
    chunk_guard_filtered_count: int,
    chunk_guard_retained_count: int,
    chunk_guard_pairwise_conflict_count: int,
    chunk_guard_pairwise_conflict_density: float,
    chunk_guard_max_conflict_penalty: float,
    chunk_guard_payload: dict[str, Any],
    chunk_guard_report_only: bool,
    chunk_guard_fallback: bool,
    chunk_guard_expectation: dict[str, Any],
    robust_signature_count: int,
    robust_signature_coverage_ratio: float,
    graph_prior_chunk_count: int,
    graph_prior_coverage_ratio: float,
    graph_prior_total: float,
    graph_seeded_chunk_count: int,
    graph_transfer_count: int,
    graph_transfer_per_seed_ratio: float,
    graph_hub_suppressed_chunk_count: int,
    graph_hub_penalty_total: float,
    topological_shield_enabled: bool,
    topological_shield_mode: str,
    topological_shield_report_only: bool,
    topological_shield_max_attenuation: float,
    topological_shield_shared_parent_attenuation: float,
    topological_shield_adjacency_attenuation: float,
    topological_shield_attenuated_chunk_count: int,
    topological_shield_coverage_ratio: float,
    topological_shield_attenuation_total: float,
    topological_shield_attenuation_per_chunk: float,
    graph_source_provider_loaded: bool,
    graph_source_projection_fallback: bool,
    graph_source_edge_count: int,
    graph_source_inbound_signal_chunk_count: int,
    graph_source_inbound_signal_coverage_ratio: float,
    graph_source_centrality_signal_chunk_count: int,
    graph_source_centrality_signal_coverage_ratio: float,
    graph_source_pagerank_signal_chunk_count: int,
    graph_source_pagerank_signal_coverage_ratio: float,
    graph_closure_enabled: bool,
    graph_closure_boosted_chunk_count: int,
    graph_closure_coverage_ratio: float,
    graph_closure_anchor_count: int,
    graph_closure_support_edge_count: int,
    graph_closure_total: float,
    multi_channel_rrf_enabled: bool,
    multi_channel_rrf_applied: bool,
    multi_channel_rrf_granularity_count: int,
    multi_channel_rrf_pool_size: int,
    multi_channel_rrf_granularity_pool_ratio: float,
    graph_lookup_enabled: bool,
    graph_lookup_reason: str,
    graph_lookup_guarded: bool,
    graph_lookup_boosted_count: int,
    graph_lookup_weight_scip: float,
    graph_lookup_weight_xref: float,
    graph_lookup_weight_query_xref: float,
    graph_lookup_weight_symbol: float,
    graph_lookup_weight_import: float,
    graph_lookup_weight_coverage: float,
    graph_lookup_candidate_count: int,
    graph_lookup_pool_size: int,
    graph_lookup_query_terms_count: int,
    graph_lookup_normalization: str,
    graph_lookup_guard_max_candidates: int,
    graph_lookup_guard_min_query_terms: int,
    graph_lookup_guard_max_query_terms: int,
    graph_lookup_query_hit_paths: int,
    graph_lookup_scip_signal_paths: int,
    graph_lookup_xref_signal_paths: int,
    graph_lookup_symbol_hit_paths: int,
    graph_lookup_import_hit_paths: int,
    graph_lookup_coverage_hit_paths: int,
    graph_lookup_max_inbound: float,
    graph_lookup_max_xref_count: float,
    graph_lookup_max_query_hits: float,
    graph_lookup_max_symbol_hits: float,
    graph_lookup_max_import_hits: float,
    graph_lookup_max_query_coverage: float,
    graph_lookup_boosted_path_ratio: float,
    graph_lookup_query_hit_path_ratio: float,
    source_plan_graph_closure_preference_enabled: bool,
    source_plan_graph_closure_bonus_candidate_count: int,
    source_plan_graph_closure_preferred_count: int,
    source_plan_granularity_preferred_count: int,
    source_plan_focused_file_promoted_count: int,
    source_plan_packed_path_count: int,
    source_plan_packed_path_ratio: float,
    source_plan_chunk_retention_ratio: float,
    source_plan_packing_reason: str,
) -> dict[str, Any]:
    payload: dict[str, Any] = {
        "candidate_paths": [
            item.get("path") for item in top_candidates if isinstance(item, dict)
        ],
        "relevant_candidate_paths": relevant_candidate_paths,
        "noise_candidate_paths": noise_candidate_paths,
        "candidate_matches": candidate_matches,
        "candidate_chunk_refs": [
            item.get("qualified_name") for item in top_chunks if isinstance(item, dict)
        ],
        "expected_hits": expected_hits,
        "chunk_hits": chunk_hits,
        "validation_tests": [
            str(item).strip() for item in validation_tests if str(item).strip()
        ][:20],
        "source_plan_evidence_summary": source_plan_evidence_summary,
        "source_plan_card_summary": source_plan_card_summary,
        "source_plan_failure_signal_summary": source_plan_failure_signal_summary,
        "stage_latency_ms": {
            "memory": round(memory_latency_ms, 3),
            "index": round(index_latency_ms, 3),
            "repomap": round(repomap_latency_ms, 3),
            "augment": round(augment_latency_ms, 3),
            "skills": round(skills_latency_ms, 3),
            "source_plan": round(source_plan_latency_ms, 3),
        },
        "retrieval_context": {
            "chunk_count": int(retrieval_context_chunk_count),
            "coverage_ratio": round(retrieval_context_coverage_ratio, 6),
            "char_count_mean": round(retrieval_context_char_count_mean, 6),
            "parent_symbol_chunk_count": int(
                contextual_sidecar_parent_symbol_chunk_count
            ),
            "parent_symbol_coverage_ratio": round(
                contextual_sidecar_parent_symbol_coverage_ratio,
                6,
            ),
            "reference_hint_chunk_count": int(
                contextual_sidecar_reference_hint_chunk_count
            ),
            "reference_hint_coverage_ratio": round(
                contextual_sidecar_reference_hint_coverage_ratio,
                6,
            ),
        },
        "chunk_contract": {
            "fallback_count": chunk_contract_fallback_count,
            "skeleton_chunk_count": chunk_contract_skeleton_chunk_count,
            "fallback_ratio": round(chunk_contract_fallback_ratio, 6),
            "skeleton_ratio": round(chunk_contract_skeleton_ratio, 6),
            "unsupported_language_fallback_count": unsupported_language_fallback_count,
            "unsupported_language_fallback_ratio": round(
                unsupported_language_fallback_ratio,
                6,
            ),
        },
        "chunk_cache_contract": {
            "present": bool(chunk_cache_contract_present),
            "fingerprint_present": bool(chunk_cache_contract_fingerprint_present),
            "metadata_aligned": bool(chunk_cache_contract_metadata_aligned),
            "file_count": int(chunk_cache_contract_file_count),
            "chunk_count": int(chunk_cache_contract_chunk_count),
        },
        "subgraph_payload": {
            "enabled": subgraph_payload_enabled,
            "reason": str(subgraph_payload.get("reason") or ""),
            "seed_path_count": subgraph_seed_path_count,
            "edge_type_count": subgraph_edge_type_count,
            "edge_total_count": subgraph_edge_total_count,
            "seed_paths": [
                str(item).strip() for item in subgraph_seed_paths if str(item).strip()
            ],
            "edge_counts": {
                str(key): max(0, int(value or 0))
                for key, value in subgraph_edge_counts.items()
                if str(key).strip()
            },
        },
        "repomap_seed": {
            "worktree_seed_count": int(repomap_worktree_seed_count),
            "subgraph_seed_count": int(repomap_subgraph_seed_count),
            "seed_candidates_count": int(repomap_seed_candidates_count),
            "cache_hit": bool(repomap_cache_hit),
            "precompute_hit": bool(repomap_precompute_hit),
        },
        "skills_budget": {
            "selected_count": int(skills_selected_count),
            "token_budget": round(skills_token_budget, 3),
            "token_budget_used": round(skills_token_budget_used, 3),
            "utilization_ratio": round(skills_token_budget_utilization_ratio, 6),
            "budget_exhausted": bool(skills_budget_exhausted),
            "skipped_for_budget_count": int(skills_skipped_for_budget_count),
        },
        "skills_routing": {
            "source": str(skills_payload.get("routing_source") or ""),
            "mode": str(skills_payload.get("routing_mode") or ""),
            "metadata_only_routing": bool(skills_metadata_only_routing),
            "route_latency_ms": round(skills_route_latency_ms, 3),
            "hydration_latency_ms": round(skills_hydration_latency_ms, 3),
            "selected_manifest_token_estimate_total": round(
                float(skills_payload.get("selected_manifest_token_estimate_total", 0.0) or 0.0),
                3,
            ),
            "hydrated_skill_count": int(skills_payload.get("hydrated_skill_count", 0) or 0),
            "hydrated_sections_count": int(
                skills_payload.get("hydrated_sections_count", 0) or 0
            ),
        },
        "plan_replay_cache": {
            "enabled": plan_replay_cache_enabled,
            "hit": plan_replay_cache_hit,
            "stale_hit_safe": plan_replay_cache_stale_hit_safe,
            "stage": str(plan_replay_cache_payload.get("stage", "")),
            "reason": str(plan_replay_cache_payload.get("reason", "")),
            "stored": bool(plan_replay_cache_payload.get("stored", False)),
            "failure_signal_summary": _as_dict(
                plan_replay_cache_payload.get("failure_signal_summary")
            ),
        },
        "slo_downgrade_signals": slo_downgrade_signals,
        "slo_budget_limits_ms": {
            "parallel_time_budget_ms": round(parallel_time_budget_ms, 3),
            "embedding_time_budget_ms": round(embedding_time_budget_ms, 3),
            "chunk_semantic_time_budget_ms": round(chunk_semantic_time_budget_ms, 3),
            "xref_time_budget_ms": round(xref_time_budget_ms, 3),
        },
        "chunk_guard": {
            "mode": chunk_guard_mode,
            "reason": chunk_guard_reason,
            "candidate_pool": chunk_guard_candidate_pool,
            "signed_chunk_count": chunk_guard_signed_chunk_count,
            "filtered_count": chunk_guard_filtered_count,
            "retained_count": chunk_guard_retained_count,
            "pairwise_conflict_count": chunk_guard_pairwise_conflict_count,
            "pairwise_conflict_density": round(
                chunk_guard_pairwise_conflict_density,
                6,
            ),
            "max_conflict_penalty": round(chunk_guard_max_conflict_penalty, 6),
            "retained_refs": list(chunk_guard_payload.get("retained_refs", []))
            if isinstance(chunk_guard_payload.get("retained_refs"), list)
            else [],
            "filtered_refs": list(chunk_guard_payload.get("filtered_refs", []))
            if isinstance(chunk_guard_payload.get("filtered_refs"), list)
            else [],
            "report_only": chunk_guard_report_only,
            "fallback": chunk_guard_fallback,
        },
        "robust_signature": {
            "count": robust_signature_count,
            "coverage_ratio": round(robust_signature_coverage_ratio, 6),
        },
        "graph_prior": {
            "chunk_count": graph_prior_chunk_count,
            "coverage_ratio": round(graph_prior_coverage_ratio, 6),
            "total": round(graph_prior_total, 6),
            "seeded_chunk_count": graph_seeded_chunk_count,
            "transfer_count": graph_transfer_count,
            "transfer_per_seed_ratio": round(graph_transfer_per_seed_ratio, 6),
            "hub_suppressed_chunk_count": graph_hub_suppressed_chunk_count,
            "hub_penalty_total": round(graph_hub_penalty_total, 6),
        },
        "topological_shield": {
            "enabled": topological_shield_enabled,
            "mode": str(topological_shield_mode),
            "report_only": topological_shield_report_only,
            "max_attenuation": round(topological_shield_max_attenuation, 6),
            "shared_parent_attenuation": round(
                topological_shield_shared_parent_attenuation, 6
            ),
            "adjacency_attenuation": round(
                topological_shield_adjacency_attenuation, 6
            ),
            "attenuated_chunk_count": topological_shield_attenuated_chunk_count,
            "coverage_ratio": round(topological_shield_coverage_ratio, 6),
            "attenuation_total": round(topological_shield_attenuation_total, 6),
            "attenuation_per_chunk": round(
                topological_shield_attenuation_per_chunk,
                6,
            ),
        },
        "graph_context_source": {
            "provider_loaded": bool(graph_source_provider_loaded),
            "projection_fallback": bool(graph_source_projection_fallback),
            "edge_count": int(graph_source_edge_count),
            "inbound_signal_chunk_count": int(graph_source_inbound_signal_chunk_count),
            "inbound_signal_coverage_ratio": round(
                graph_source_inbound_signal_coverage_ratio,
                6,
            ),
            "centrality_signal_chunk_count": int(
                graph_source_centrality_signal_chunk_count
            ),
            "centrality_signal_coverage_ratio": round(
                graph_source_centrality_signal_coverage_ratio,
                6,
            ),
            "pagerank_signal_chunk_count": int(
                graph_source_pagerank_signal_chunk_count
            ),
            "pagerank_signal_coverage_ratio": round(
                graph_source_pagerank_signal_coverage_ratio,
                6,
            ),
        },
        "graph_closure": {
            "enabled": graph_closure_enabled,
            "boosted_chunk_count": graph_closure_boosted_chunk_count,
            "coverage_ratio": round(graph_closure_coverage_ratio, 6),
            "anchor_count": graph_closure_anchor_count,
            "support_edge_count": graph_closure_support_edge_count,
            "total": round(graph_closure_total, 6),
        },
        "index_fusion_granularity": {
            "enabled": multi_channel_rrf_enabled,
            "applied": multi_channel_rrf_applied,
            "granularity_count": multi_channel_rrf_granularity_count,
            "pool_size": multi_channel_rrf_pool_size,
            "granularity_pool_ratio": round(
                multi_channel_rrf_granularity_pool_ratio,
                6,
            ),
        },
        "graph_lookup": {
            "enabled": graph_lookup_enabled,
            "reason": str(graph_lookup_reason),
            "guarded": bool(graph_lookup_guarded),
            "boosted_count": graph_lookup_boosted_count,
            "weights": {
                "scip": round(graph_lookup_weight_scip, 6),
                "xref": round(graph_lookup_weight_xref, 6),
                "query_xref": round(graph_lookup_weight_query_xref, 6),
                "symbol": round(graph_lookup_weight_symbol, 6),
                "import": round(graph_lookup_weight_import, 6),
                "coverage": round(graph_lookup_weight_coverage, 6),
            },
            "candidate_count": graph_lookup_candidate_count,
            "pool_size": graph_lookup_pool_size,
            "query_terms_count": graph_lookup_query_terms_count,
            "normalization": str(graph_lookup_normalization),
            "guard_max_candidates": graph_lookup_guard_max_candidates,
            "guard_min_query_terms": graph_lookup_guard_min_query_terms,
            "guard_max_query_terms": graph_lookup_guard_max_query_terms,
            "query_hit_paths": graph_lookup_query_hit_paths,
            "scip_signal_paths": graph_lookup_scip_signal_paths,
            "xref_signal_paths": graph_lookup_xref_signal_paths,
            "symbol_hit_paths": graph_lookup_symbol_hit_paths,
            "import_hit_paths": graph_lookup_import_hit_paths,
            "coverage_hit_paths": graph_lookup_coverage_hit_paths,
            "max_inbound": round(graph_lookup_max_inbound, 6),
            "max_xref_count": round(graph_lookup_max_xref_count, 6),
            "max_query_hits": round(graph_lookup_max_query_hits, 6),
            "max_symbol_hits": round(graph_lookup_max_symbol_hits, 6),
            "max_import_hits": round(graph_lookup_max_import_hits, 6),
            "max_query_coverage": round(graph_lookup_max_query_coverage, 6),
            "boosted_path_ratio": round(graph_lookup_boosted_path_ratio, 6),
            "query_hit_path_ratio": round(graph_lookup_query_hit_path_ratio, 6),
        },
        "source_plan_packing": {
            "graph_closure_preference_enabled": (
                source_plan_graph_closure_preference_enabled
            ),
            "graph_closure_bonus_candidate_count": (
                source_plan_graph_closure_bonus_candidate_count
            ),
            "graph_closure_preferred_count": source_plan_graph_closure_preferred_count,
            "granularity_preferred_count": source_plan_granularity_preferred_count,
            "focused_file_promoted_count": source_plan_focused_file_promoted_count,
            "packed_path_count": source_plan_packed_path_count,
            "packed_path_ratio": round(source_plan_packed_path_ratio, 6),
            "chunk_retention_ratio": round(source_plan_chunk_retention_ratio, 6),
            "reason": source_plan_packing_reason,
        },
        "year2_normalized_kpis": {
            "skills_token_budget_utilization_ratio": round(
                skills_token_budget_utilization_ratio,
                6,
            ),
            "source_plan_chunk_retention_ratio": round(
                source_plan_chunk_retention_ratio,
                6,
            ),
            "source_plan_packed_path_ratio": round(
                source_plan_packed_path_ratio,
                6,
            ),
            "graph_transfer_per_seed_ratio": round(
                graph_transfer_per_seed_ratio,
                6,
            ),
            "chunk_guard_pairwise_conflict_density": round(
                chunk_guard_pairwise_conflict_density,
                6,
            ),
            "topological_shield_attenuation_per_chunk": round(
                topological_shield_attenuation_per_chunk,
                6,
            ),
        },
    }
    if (
        included_candidate_paths
        or included_candidate_globs
        or excluded_candidate_paths
        or excluded_candidate_globs
    ):
        payload["candidate_path_filters"] = {
            "include_paths": included_candidate_paths,
            "include_globs": included_candidate_globs,
            "exclude_paths": excluded_candidate_paths,
            "exclude_globs": excluded_candidate_globs,
        }
    if chunk_stage_miss["applicable"]:
        payload["chunk_stage_miss_details"] = {
            "oracle_file_path": str(chunk_stage_miss["oracle_file_path"]),
            "oracle_chunk_ref": dict(chunk_stage_miss["oracle_chunk_ref"]),
            "file_present": bool(chunk_stage_miss["file_present"]),
            "raw_chunk_present": bool(chunk_stage_miss["raw_chunk_present"]),
            "source_plan_chunk_present": bool(
                chunk_stage_miss["source_plan_chunk_present"]
            ),
        }
    if chunk_guard_expectation["applicable"]:
        payload["chunk_guard_expectation"] = {
            "scenario": str(chunk_guard_expectation["scenario"]),
            "expected_retained_refs": list(
                chunk_guard_expectation["expected_retained_refs"]
            ),
            "expected_filtered_refs": list(
                chunk_guard_expectation["expected_filtered_refs"]
            ),
            "retained_hits": list(chunk_guard_expectation["retained_hits"]),
            "filtered_hits": list(chunk_guard_expectation["filtered_hits"]),
            "expected_retained_hit": bool(
                chunk_guard_expectation["expected_retained_hit"]
            ),
            "expected_filtered_hit_count": int(
                chunk_guard_expectation["expected_filtered_hit_count"]
            ),
            "expected_filtered_hit_rate": round(
                float(chunk_guard_expectation["expected_filtered_hit_rate"]),
                6,
            ),
            "report_only_improved": bool(
                chunk_guard_expectation["report_only_improved"]
            ),
        }
    return payload


__all__ = ["build_case_detail_payload"]
