from __future__ import annotations

import csv
import math
from collections import Counter
from pathlib import Path
from statistics import mean


BASE = Path("frame_audit_001_bfcl")
PROCESSED = BASE / "data" / "processed"
OUTPUTS = BASE / "outputs"

BASELINE = PROCESSED / "bfcl_v4_baseline.csv"
PROFILE_RESULTS = PROCESSED / "bfcl_profile_results.csv"
SENSITIVITY_RESULTS = PROCESSED / "bfcl_sensitivity_results.csv"
PROFILE_REPORT = OUTPUTS / "BFCL_PROFILE_RESULTS_REPORT.md"
AUDIT_REPORT = OUTPUTS / "BFCL_CALCULATION_AND_MATERIALITY_AUDIT.md"

SCORING_TASK_COUNT = 5088
PROFILE_NAMES = {
    "A": "High-volume low-risk automation",
    "B": "Regulated or high-consequence workflow",
    "C": "Multi-turn enterprise agent",
    "D": "Cost-constrained general tool user",
}
PUBLISHED_WINNER_RANK = "1"


def read_csv(path: Path) -> list[dict[str, str]]:
    with path.open("r", encoding="utf-8", newline="") as f:
        return list(csv.DictReader(f))


def write_csv(path: Path, rows: list[dict[str, str]]) -> None:
    if not rows:
        path.write_text("", encoding="utf-8")
        return
    fieldnames = list(rows[0].keys())
    with path.open("w", encoding="utf-8", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(rows)


def f(value: str | None) -> float | None:
    if value is None or str(value).strip() == "":
        return None
    return float(value)


def avg(values: list[float | None]) -> float | None:
    if not values or any(v is None for v in values):
        return None
    return sum(v for v in values if v is not None) / len(values)


def lower_better_scores(values: dict[str, float | None]) -> dict[str, float | None]:
    present = {k: v for k, v in values.items() if v is not None and math.isfinite(v)}
    if not present:
        return {k: None for k in values}
    lo = min(present.values())
    hi = max(present.values())
    out: dict[str, float | None] = {}
    for k, v in values.items():
        if k not in present:
            out[k] = None
        elif hi == lo:
            out[k] = 100.0
        else:
            out[k] = 100.0 * (hi - v) / (hi - lo)
    return out


def latency_score(p95: float | None, target: float) -> float | None:
    if p95 is None or p95 <= 0:
        return None
    return 100.0 / max(1.0, p95 / target)


def cost_per_success(cost: float | None, success_pct: float | None) -> float | None:
    if cost is None or success_pct is None or success_pct <= 0:
        return None
    return cost / (SCORING_TASK_COUNT * (success_pct / 100.0))


def row_metrics(row: dict[str, str]) -> dict[str, float | None]:
    format_risk = None
    if f(row["format_sensitivity_max_delta"]) is not None and f(row["format_sensitivity_standard_deviation"]) is not None:
        format_risk = f(row["format_sensitivity_max_delta"]) + f(row["format_sensitivity_standard_deviation"])
    return {
        "single_turn": avg(
            [
                f(row["non_live_simple_ast"]),
                f(row["non_live_multiple_ast"]),
                f(row["non_live_parallel_ast"]),
                f(row["non_live_parallel_multiple_ast"]),
                f(row["live_simple_ast"]),
                f(row["live_multiple_ast"]),
                f(row["live_parallel_ast"]),
                f(row["live_parallel_multiple_ast"]),
            ]
        ),
        "relevance_behavior": avg([f(row["relevance_detection"]), f(row["hallucination_irrelevance_detection"])]),
        "single_turn_summary": avg([f(row["live_acc"]), f(row["non_live_ast_acc"])]),
        "agentic": f(row["reconstructed_agentic_component"]),
        "multi_turn": f(row["multi_turn_acc"]),
        "memory": f(row["memory_acc"]),
        "web_search": f(row["web_search_acc"]),
        "task_success_d": avg(
            [
                f(row["published_overall_score"]),
                f(row["non_live_ast_acc"]),
                f(row["live_acc"]),
                f(row["multi_turn_acc"]),
            ]
        ),
        "format_risk": format_risk,
    }


def missing(row: dict[str, str], fields: list[str]) -> list[str]:
    return [field for field in fields if f(row.get(field)) is None]


def disqualify(profile_id: str, row: dict[str, str]) -> list[str]:
    reasons: list[str] = []
    if profile_id == "A":
        required = [
            "non_live_simple_ast",
            "non_live_multiple_ast",
            "non_live_parallel_ast",
            "non_live_parallel_multiple_ast",
            "live_simple_ast",
            "live_multiple_ast",
            "live_parallel_ast",
            "live_parallel_multiple_ast",
            "relevance_detection",
            "hallucination_irrelevance_detection",
            "total_cost_usd",
            "latency_mean_s",
            "latency_standard_deviation_s",
            "latency_95th_percentile_s",
        ]
        miss = missing(row, required)
        if miss:
            reasons.append("missing required fields: " + "; ".join(miss))
        if f(row["hallucination_irrelevance_detection"]) is not None and f(row["hallucination_irrelevance_detection"]) < 70:
            reasons.append("Irrelevance Detection below 70%")
        if f(row["latency_95th_percentile_s"]) is not None and f(row["latency_95th_percentile_s"]) > 20:
            reasons.append("Latency 95th Percentile above 20 seconds")
    elif profile_id == "B":
        required = [
            "relevance_detection",
            "hallucination_irrelevance_detection",
            "multi_turn_base",
            "multi_turn_miss_func",
            "multi_turn_miss_param",
            "multi_turn_long_context",
            "live_acc",
            "non_live_ast_acc",
            "latency_95th_percentile_s",
            "total_cost_usd",
        ]
        miss = missing(row, required)
        if miss:
            reasons.append("missing required safety-related fields: " + "; ".join(miss))
        if f(row["hallucination_irrelevance_detection"]) is not None and f(row["hallucination_irrelevance_detection"]) < 90:
            reasons.append("Irrelevance Detection below 90%")
        if f(row["relevance_detection"]) is not None and f(row["relevance_detection"]) < 85:
            reasons.append("Relevance Detection below 85%")
        if f(row["multi_turn_miss_func"]) is not None and f(row["multi_turn_miss_func"]) < 70:
            reasons.append("Multi Turn Miss Func below 70%")
        if f(row["latency_95th_percentile_s"]) is not None and f(row["latency_95th_percentile_s"]) > 60:
            reasons.append("Latency 95th Percentile above 60 seconds")
    elif profile_id == "C":
        required = [
            "multi_turn_base",
            "multi_turn_miss_func",
            "multi_turn_miss_param",
            "multi_turn_long_context",
            "memory_kv",
            "memory_vector",
            "memory_recursive_summarization",
            "web_search_base",
            "web_search_no_snippet",
            "relevance_detection",
            "hallucination_irrelevance_detection",
            "latency_95th_percentile_s",
            "total_cost_usd",
        ]
        miss = missing(row, required)
        if miss:
            reasons.append("missing required multi-turn/agentic fields: " + "; ".join(miss))
        if f(row["multi_turn_acc"]) is not None and f(row["multi_turn_acc"]) < 60:
            reasons.append("Multi Turn Acc below 60%")
        if f(row["latency_95th_percentile_s"]) is not None and f(row["latency_95th_percentile_s"]) > 60:
            reasons.append("Latency 95th Percentile above 60 seconds")
    elif profile_id == "D":
        required = [
            "published_overall_score",
            "non_live_ast_acc",
            "live_acc",
            "multi_turn_acc",
            "relevance_detection",
            "hallucination_irrelevance_detection",
            "total_cost_usd",
            "latency_mean_s",
            "latency_standard_deviation_s",
            "latency_95th_percentile_s",
        ]
        miss = missing(row, required)
        if miss:
            reasons.append("missing required general tool-user fields: " + "; ".join(miss))
        if f(row["hallucination_irrelevance_detection"]) is not None and f(row["hallucination_irrelevance_detection"]) < 70:
            reasons.append("Irrelevance Detection below 70%")
        if f(row["latency_95th_percentile_s"]) is not None and f(row["latency_95th_percentile_s"]) > 45:
            reasons.append("Latency 95th Percentile above 45 seconds")
    return reasons


def eligible_rows(baseline: list[dict[str, str]], profile_id: str) -> list[dict[str, str]]:
    return [row for row in baseline if not disqualify(profile_id, row)]


def profile_success(profile_id: str, row: dict[str, str]) -> float | None:
    metrics = row_metrics(row)
    if profile_id == "A":
        return metrics["single_turn"]
    if profile_id == "B":
        return avg([metrics["relevance_behavior"], metrics["multi_turn"], metrics["agentic"], metrics["single_turn_summary"]])
    if profile_id == "C":
        return metrics["multi_turn"]
    if profile_id == "D":
        return metrics["task_success_d"]
    return None


def profile_aux(baseline: list[dict[str, str]], profile_id: str) -> tuple[list[dict[str, str]], dict[str, float | None], dict[str, float | None]]:
    elig = eligible_rows(baseline, profile_id)
    cost_scores = lower_better_scores(
        {
            row["model_identifier"]: cost_per_success(f(row["total_cost_usd"]), profile_success(profile_id, row))
            for row in elig
        }
    )
    format_scores = lower_better_scores({row["model_identifier"]: row_metrics(row)["format_risk"] for row in elig})
    return elig, cost_scores, format_scores


def profile_terms(
    baseline: list[dict[str, str]],
    profile_id: str,
    row: dict[str, str],
    remove: str | None = None,
    capability_only: bool = False,
) -> list[tuple[str, str, float, float]]:
    metrics = row_metrics(row)
    _, cost_scores, format_scores = profile_aux(baseline, profile_id)
    model = row["model_identifier"]
    p95 = f(row["latency_95th_percentile_s"])
    terms: list[tuple[str, str, float, float | None]] = []
    if profile_id == "A":
        terms = [
            ("benchmark_capability", "single_turn", 40, metrics["single_turn"]),
            ("reliability_workflow", "relevance_behavior", 20, metrics["relevance_behavior"]),
            ("cost", "cost_efficiency", 25, cost_scores.get(model)),
            ("latency", "latency", 15, latency_score(p95, 10)),
        ]
    elif profile_id == "B":
        cost_latency = avg([cost_scores.get(model), latency_score(p95, 60)])
        terms = [
            ("reliability_workflow", "hallucination_abstention_behavior", 30, metrics["relevance_behavior"]),
            ("benchmark_capability", "multi_turn_correctness", 25, metrics["multi_turn"]),
            ("benchmark_capability", "agentic_web_search_memory", 15, metrics["agentic"]),
            ("benchmark_capability", "single_turn_tool_call_accuracy", 15, metrics["single_turn_summary"]),
            ("format", "format_robustness", 10, format_scores.get(model)),
            ("cost_latency", "cost_latency", 5, cost_latency),
        ]
    elif profile_id == "C":
        terms = [
            ("benchmark_capability", "multi_turn_performance", 35, metrics["multi_turn"]),
            ("benchmark_capability", "agentic_memory_performance", 25, metrics["memory"]),
            ("benchmark_capability", "web_search_performance", 15, metrics["web_search"]),
            ("reliability_workflow", "relevance_behavior", 10, metrics["relevance_behavior"]),
            ("latency", "latency", 10, latency_score(p95, 30)),
            ("cost", "cost", 5, cost_scores.get(model)),
        ]
    elif profile_id == "D":
        latency_adjusted = None
        if metrics["task_success_d"] is not None and latency_score(p95, 30) is not None:
            latency_adjusted = metrics["task_success_d"] * (latency_score(p95, 30) / 100.0)
        terms = [
            ("benchmark_capability", "task_success", 35, metrics["task_success_d"]),
            ("cost", "cost_efficiency", 35, cost_scores.get(model)),
            ("latency", "latency_adjusted_success", 15, latency_adjusted),
            ("reliability_workflow", "relevance_behavior", 10, metrics["relevance_behavior"]),
            ("format", "format_robustness", 5, format_scores.get(model)),
        ]
    if capability_only:
        terms = [term for term in terms if term[0] in {"benchmark_capability", "reliability_workflow", "format"}]
    if remove:
        terms = [term for term in terms if term[0] != remove and term[1] != remove]
    return [(kind, name, weight, value) for kind, name, weight, value in terms if value is not None]


def score_from_terms(terms: list[tuple[str, str, float, float]]) -> float | None:
    total_weight = sum(weight for _, _, weight, _ in terms)
    if total_weight == 0:
        return None
    return sum(weight * value for _, _, weight, value in terms) / total_weight


def profile_score(baseline: list[dict[str, str]], profile_id: str, row: dict[str, str], remove: str | None = None, capability_only: bool = False) -> float | None:
    return score_from_terms(profile_terms(baseline, profile_id, row, remove=remove, capability_only=capability_only))


def ranked_for(baseline: list[dict[str, str]], profile_id: str, remove: str | None = None, capability_only: bool = False) -> list[tuple[float, dict[str, str]]]:
    scored = []
    for row in eligible_rows(baseline, profile_id):
        score = profile_score(baseline, profile_id, row, remove=remove, capability_only=capability_only)
        if score is not None:
            scored.append((score, row))
    return sorted(scored, key=lambda item: (-item[0], int(item[1]["official_rank"])))


def verify_profiles(baseline: list[dict[str, str]], stored: list[dict[str, str]]) -> dict[str, str]:
    stored_by_key = {(row["profile_id"], row["model_identifier"]): row for row in stored}
    max_score_delta = 0.0
    eligibility_mismatches = 0
    rank_mismatches = 0
    reason_mismatches = 0
    profile_counts: dict[str, tuple[int, int]] = {}
    for profile_id in ["A", "B", "C", "D"]:
        recomputed_ranking = ranked_for(baseline, profile_id)
        rank_by_model = {row["model_identifier"]: rank for rank, (_, row) in enumerate(recomputed_ranking, start=1)}
        elig = 0
        disq = 0
        for row in baseline:
            key = (profile_id, row["model_identifier"])
            old = stored_by_key[key]
            reasons = disqualify(profile_id, row)
            expected_eligible = not reasons
            old_eligible = old["eligible"].lower() == "true"
            if expected_eligible:
                elig += 1
            else:
                disq += 1
            if expected_eligible != old_eligible:
                eligibility_mismatches += 1
            if "; ".join(reasons) != old["disqualification_reason"]:
                reason_mismatches += 1
            if expected_eligible:
                expected_score = profile_score(baseline, profile_id, row)
                old_score = f(old["profile_weighted_score"])
                if expected_score is not None and old_score is not None:
                    max_score_delta = max(max_score_delta, abs(expected_score - old_score))
                expected_rank = rank_by_model[row["model_identifier"]]
                old_rank = int(old["profile_rank"])
                if expected_rank != old_rank:
                    rank_mismatches += 1
        profile_counts[profile_id] = (elig, disq)
    return {
        "max_score_delta": f"{max_score_delta:.9f}",
        "eligibility_mismatches": str(eligibility_mismatches),
        "rank_mismatches": str(rank_mismatches),
        "reason_mismatches": str(reason_mismatches),
        "profile_counts": "; ".join(f"{pid}: {e} eligible/{d} disqualified" for pid, (e, d) in profile_counts.items()),
    }


def fix_sensitivity_outputs() -> dict[str, str]:
    rows = read_csv(SENSITIVITY_RESULTS)
    fixes = 0
    for row in rows:
        if not row.get("sensitivity_rank") and row.get("rank"):
            row["sensitivity_rank"] = row["rank"]
            fixes += 1
    write_csv(SENSITIVITY_RESULTS, rows)

    test_labels = {
        "equal_component_weighting": "Equal component weighting",
        "hallucination_as_hard_constraint": "Hallucination as a hard constraint",
        "multi_turn_minimum_threshold": "Multi-turn minimum threshold",
        "cost_per_successful_call": "Cost per successful call",
        "latency_adjusted_success": "Latency-adjusted success",
        "exclusion_of_incomplete_model_entries": "Exclusion of incomplete model entries",
    }
    summary_lines = ["## Sensitivity Tests", ""]
    for test, label in test_labels.items():
        test_rows = [row for row in rows if row["sensitivity_test"] == test]
        eligible = [row for row in test_rows if row["eligible"].lower() == "true"]
        disq = [row for row in test_rows if row["eligible"].lower() != "true"]
        if eligible:
            top = min(eligible, key=lambda row: int(row["sensitivity_rank"]))
            summary_lines.append(
                f"- {label}: selected `{top['model_identifier']}`; eligible {len(eligible)}; disqualified {len(disq)}; published rank {top['published_rank']}; rank difference {top['rank_difference_from_published']}."
            )
        else:
            summary_lines.append(f"- {label}: no eligible model; eligible {len(eligible)}; disqualified {len(disq)}.")
    summary_lines.append("")

    text = PROFILE_REPORT.read_text(encoding="utf-8")
    before, marker, rest = text.partition("## Sensitivity Tests")
    if marker:
        _, marker2, after = rest.partition("## Interpretation")
        if marker2:
            text = before + "\n".join(summary_lines) + "## Interpretation" + after
            PROFILE_REPORT.write_text(text, encoding="utf-8")
    return {"sensitivity_rank_cells_filled": str(fixes)}


def decomposition_rows(baseline: list[dict[str, str]], profile_id: str) -> list[dict[str, str]]:
    ranking = ranked_for(baseline, profile_id)
    published = next(row for row in baseline if row["official_rank"] == PUBLISHED_WINNER_RANK)
    targets = [
        ("profile_selected_model", ranking[0][1]),
        ("published_bfcl_winner", published),
        ("second_ranked_profile_model", ranking[1][1]),
    ]
    seen = set()
    rows = []
    for role, row in targets:
        if (role, row["model_identifier"]) in seen:
            continue
        seen.add((role, row["model_identifier"]))
        terms = profile_terms(baseline, profile_id, row)
        total_weight = sum(weight for _, _, weight, _ in terms)
        grouped = Counter()
        raw = {}
        for kind, name, weight, value in terms:
            grouped[kind] += weight * value / total_weight
            raw[name] = value
        rows.append(
            {
                "profile_id": profile_id,
                "role": role,
                "model": row["model_identifier"],
                "published_rank": row["official_rank"],
                "profile_score": profile_score(baseline, profile_id, row),
                "benchmark_capability_contribution": grouped["benchmark_capability"],
                "cost_contribution": grouped["cost"],
                "latency_contribution": grouped["latency"],
                "reliability_or_workflow_contribution": grouped["reliability_workflow"],
                "optional_format_sensitivity_contribution": grouped["format"],
                "raw_terms": "; ".join(f"{k}={v:.3f}" for k, v in raw.items()),
                "total_cost_usd": f(row["total_cost_usd"]),
                "latency_p95_s": f(row["latency_95th_percentile_s"]),
            }
        )
    return rows


def leave_one_factor_rows(baseline: list[dict[str, str]]) -> list[dict[str, str]]:
    rows = []
    checks = {
        "A": [
            ("full_registered_profile", None, False),
            ("remove_cost", "cost_efficiency", False),
            ("remove_latency", "latency", False),
            ("remove_single_turn_capability", "single_turn", False),
            ("remove_relevance_reliability", "relevance_behavior", False),
            ("capability_only_weighting", None, True),
        ],
        "D": [
            ("full_registered_profile", None, False),
            ("remove_cost", "cost_efficiency", False),
            ("remove_latency", "latency_adjusted_success", False),
            ("remove_task_success_capability", "task_success", False),
            ("remove_relevance_reliability", "relevance_behavior", False),
            ("remove_optional_format_sensitivity", "format_robustness", False),
            ("capability_only_weighting", None, True),
        ],
    }
    published_winner = next(row for row in baseline if row["official_rank"] == PUBLISHED_WINNER_RANK)["model_identifier"]
    for profile_id, profile_checks in checks.items():
        for check_name, remove, capability_only in profile_checks:
            ranking = ranked_for(baseline, profile_id, remove=remove, capability_only=capability_only)
            top_score, top_row = ranking[0]
            published_rows = [item for item in ranking if item[1]["model_identifier"] == published_winner]
            published_score = published_rows[0][0] if published_rows else None
            rows.append(
                {
                    "profile_id": profile_id,
                    "check": check_name,
                    "selected_model": top_row["model_identifier"],
                    "selected_published_rank": top_row["official_rank"],
                    "selected_score": top_score,
                    "published_winner_score_under_check": published_score,
                    "flip_survives": top_row["model_identifier"] != published_winner,
                }
            )
    return rows


def profile_b_threshold_audit(baseline: list[dict[str, str]]) -> tuple[dict[str, int], Counter[tuple[str, ...]]]:
    counts = Counter()
    combos: Counter[tuple[str, ...]] = Counter()
    required = [
        "relevance_detection",
        "hallucination_irrelevance_detection",
        "multi_turn_base",
        "multi_turn_miss_func",
        "multi_turn_miss_param",
        "multi_turn_long_context",
        "live_acc",
        "non_live_ast_acc",
        "latency_95th_percentile_s",
        "total_cost_usd",
    ]
    for row in baseline:
        fails = []
        if any(f(row[field]) is None for field in required):
            fails.append("missing required safety-related fields")
        if f(row["hallucination_irrelevance_detection"]) is not None and f(row["hallucination_irrelevance_detection"]) < 90:
            fails.append("Irrelevance Detection below 90%")
        if f(row["relevance_detection"]) is not None and f(row["relevance_detection"]) < 85:
            fails.append("Relevance Detection below 85%")
        if f(row["multi_turn_miss_func"]) is not None and f(row["multi_turn_miss_func"]) < 70:
            fails.append("Multi Turn Miss Func below 70%")
        if f(row["latency_95th_percentile_s"]) is not None and f(row["latency_95th_percentile_s"]) > 60:
            fails.append("Latency 95th Percentile above 60 seconds")
        for fail in fails:
            counts[fail] += 1
        combos[tuple(sorted(fails))] += 1
    return dict(counts), combos


def procurement_rows(baseline: list[dict[str, str]]) -> list[dict[str, str]]:
    names = [
        ("A", ranked_for(baseline, "A")[0][1]["model_identifier"]),
        ("C", ranked_for(baseline, "C")[0][1]["model_identifier"]),
        ("D", ranked_for(baseline, "D")[0][1]["model_identifier"]),
    ]
    out = []
    for profile_id, name in names:
        row = next(item for item in baseline if item["model_identifier"] == name)
        out.append(
            {
                "profile_id": profile_id,
                "model": name,
                "organization": row["organization"],
                "license": row["license"],
                "model_link_present": "yes" if row["model_link"] else "no",
                "model_update_date_detected": row["model_update_date_detected"] or "not encoded in model identifier",
                "leaderboard_last_updated": row["leaderboard_last_updated"],
                "bfcl_eval_package": row["bfcl_eval_package"],
                "bfcl_eval_commit": row["bfcl_eval_commit"],
                "archive_snapshot": row["archive_snapshot"],
                "procurement_plausibility_from_snapshot_only": "plausible from frozen BFCL metadata; live availability not rechecked",
            }
        )
    return out


def md_table(rows: list[dict], fields: list[tuple[str, str]]) -> list[str]:
    lines = []
    lines.append("| " + " | ".join(label for label, _ in fields) + " |")
    lines.append("| " + " | ".join("---" for _ in fields) + " |")
    for row in rows:
        vals = []
        for _, key in fields:
            value = row.get(key, "")
            if isinstance(value, float):
                vals.append(f"{value:.2f}")
            elif isinstance(value, bool):
                vals.append("Yes" if value else "No")
            else:
                vals.append(str(value))
        lines.append("| " + " | ".join(vals) + " |")
    return lines


def write_audit_report(
    baseline: list[dict[str, str]],
    verification: dict[str, str],
    fix_stats: dict[str, str],
    decomp: list[dict],
    loo: list[dict],
    threshold_counts: dict[str, int],
    threshold_combos: Counter[tuple[str, ...]],
    procurement: list[dict[str, str]],
) -> str:
    published = next(row for row in baseline if row["official_rank"] == PUBLISHED_WINNER_RANK)
    a_full = next(row for row in loo if row["profile_id"] == "A" and row["check"] == "full_registered_profile")
    d_full = next(row for row in loo if row["profile_id"] == "D" and row["check"] == "full_registered_profile")
    a_without_cost = next(row for row in loo if row["profile_id"] == "A" and row["check"] == "remove_cost")
    a_without_latency = next(row for row in loo if row["profile_id"] == "A" and row["check"] == "remove_latency")
    a_capability = next(row for row in loo if row["profile_id"] == "A" and row["check"] == "capability_only_weighting")
    d_without_cost = next(row for row in loo if row["profile_id"] == "D" and row["check"] == "remove_cost")
    d_without_latency = next(row for row in loo if row["profile_id"] == "D" and row["check"] == "remove_latency")
    d_capability = next(row for row in loo if row["profile_id"] == "D" and row["check"] == "capability_only_weighting")
    material_table = [
        {
            "profile": "A",
            "selected_model": a_full["selected_model"],
            "survive_without_cost": a_without_cost["flip_survives"],
            "survive_without_latency": a_without_latency["flip_survives"],
            "survive_capability_only": a_capability["flip_survives"],
            "large_enough": "Yes: profile gap vs published winner is about 9.23 points and capability-only still rejects the aggregate winner.",
            "questionable_input": "No for the aggregate-vs-profile flip; exact selected model changes when cost is removed.",
        },
        {
            "profile": "B",
            "selected_model": "none",
            "survive_without_cost": "N/A",
            "survive_without_latency": "N/A",
            "survive_capability_only": "N/A",
            "large_enough": "No eligible model; threshold audit only.",
            "questionable_input": "Conjunction is very strict; dominated by Multi Turn Miss Func threshold.",
        },
        {
            "profile": "C",
            "selected_model": ranked_for(baseline, "C")[0][1]["model_identifier"],
            "survive_without_cost": "N/A",
            "survive_without_latency": "N/A",
            "survive_capability_only": "N/A",
            "large_enough": "No flip from published aggregate winner.",
            "questionable_input": "No decision flip to validate.",
        },
        {
            "profile": "D",
            "selected_model": d_full["selected_model"],
            "survive_without_cost": d_without_cost["flip_survives"],
            "survive_without_latency": d_without_latency["flip_survives"],
            "survive_capability_only": d_capability["flip_survives"],
            "large_enough": "Conditional: profile gap is about 6.90 points, but the exact full-profile winner depends on cost.",
            "questionable_input": "Yes: the full-profile winner is cost-dependent and BFCL cost comparability is limited.",
        },
    ]

    lines: list[str] = []
    lines.append("# BFCL Calculation And Materiality Audit")
    lines.append("")
    lines.append("Status: internal calculation audit only. No source data, buyer-profile definitions, or thresholds were changed. No API calls were made.")
    lines.append("")
    lines.append("## 1. Sensitivity Summary Correction")
    lines.append("")
    lines.append("The previous profile report contained contradictory sensitivity lines such as `no eligible model; eligible 109; disqualified 0`. The underlying `bfcl_sensitivity_results.csv` had rank values in a fallback `rank` column but an empty `sensitivity_rank` column, so the report lookup missed eligible winners.")
    lines.append("")
    lines.append(f"- Filled `sensitivity_rank` cells from the existing `rank` column: {fix_stats['sensitivity_rank_cells_filled']}.")
    lines.append("- Rewrote the `## Sensitivity Tests` section of `BFCL_PROFILE_RESULTS_REPORT.md` using the corrected rank field.")
    lines.append("- No frozen source data or buyer-profile definitions were changed.")
    lines.append("")
    lines.append("## 2. Calculation Verification")
    lines.append("")
    lines.append("Each Profile A-D score, eligibility decision, disqualification reason, and rank was recomputed from `bfcl_v4_baseline.csv` using the frozen profile definitions.")
    lines.append("")
    lines.append(f"- Profile counts: {verification['profile_counts']}.")
    lines.append(f"- Eligibility mismatches: {verification['eligibility_mismatches']}.")
    lines.append(f"- Disqualification-reason mismatches: {verification['reason_mismatches']}.")
    lines.append(f"- Rank mismatches: {verification['rank_mismatches']}.")
    lines.append(f"- Maximum profile score difference versus stored CSV: {verification['max_score_delta']}.")
    lines.append("")
    lines.append("## 3. Documented BFCL Data")
    lines.append("")
    lines.append(f"- Published aggregate comparator: `{published['model_identifier']}` at official rank 1.")
    lines.append(f"- Model variants in processed baseline: {len(baseline)}.")
    lines.append("- Used documented BFCL fields already frozen in `bfcl_v4_baseline.csv`: overall score, component scores, cost, latency, organization, license, model link, leaderboard update, package, commit, and archive snapshot.")
    lines.append("")
    lines.append("## 4. Pre-Registered Buyer Assumptions")
    lines.append("")
    lines.append("- Profile A emphasizes single-turn tool-call accuracy, relevance/irrelevance behavior, cost efficiency, and latency.")
    lines.append("- Profile B applies strict regulated-workflow thresholds for hallucination/relevance, multi-turn missing-function behavior, and latency.")
    lines.append("- Profile C emphasizes multi-turn, memory, web search, reliability, latency, and cost.")
    lines.append("- Profile D emphasizes general task success, cost per expected success, latency-adjusted success, relevance/irrelevance behavior, and optional format robustness.")
    lines.append("- Optional format sensitivity was only used where BFCL provided fields for that model variant; absent optional format terms were omitted and remaining registered weights were renormalized.")
    lines.append("")
    lines.append("## 5. Profile A And D Score Decomposition")
    lines.append("")
    lines.extend(
        md_table(
            decomp,
            [
                ("Profile", "profile_id"),
                ("Role", "role"),
                ("Model", "model"),
                ("Published Rank", "published_rank"),
                ("Profile Score", "profile_score"),
                ("Benchmark Capability", "benchmark_capability_contribution"),
                ("Cost", "cost_contribution"),
                ("Latency", "latency_contribution"),
                ("Reliability/Workflow", "reliability_or_workflow_contribution"),
                ("Format", "optional_format_sensitivity_contribution"),
                ("Raw Terms", "raw_terms"),
            ],
        )
    )
    lines.append("")
    lines.append("## 6. Leave-One-Factor-Out Checks")
    lines.append("")
    lines.append("These are diagnostic checks only. They remove one registered factor at a time and renormalize the remaining registered factors; they do not redefine or replace the frozen buyer profiles.")
    lines.append("")
    lines.extend(
        md_table(
            loo,
            [
                ("Profile", "profile_id"),
                ("Check", "check"),
                ("Selected Model", "selected_model"),
                ("Published Rank", "selected_published_rank"),
                ("Selected Score", "selected_score"),
                ("Published Winner Score", "published_winner_score_under_check"),
                ("Flip Survives", "flip_survives"),
            ],
        )
    )
    lines.append("")
    lines.append("Profile A: the decision flip survives without cost, without latency, and under capability-only weighting. The exact selected model changes under some diagnostics, but the published aggregate winner is not selected once the workflow frame is narrowed to low-risk high-volume single-turn automation.")
    lines.append("")
    lines.append("Profile D: the full-profile selected model does not survive removal of cost; removing cost returns the published aggregate winner. The D flip is therefore materially cost-dependent.")
    lines.append("")
    lines.append("## 7. BFCL Cost Comparability Limitations")
    lines.append("")
    lines.append("- Prompted versus native function-calling variants may not carry equivalent tool-schema serialization, parser behavior, or token accounting.")
    lines.append("- Reasoning and non-reasoning variants may differ in hidden reasoning effort, output length, latency, and provider billing behavior; the frozen baseline does not expose reasoning-token controls.")
    lines.append("- Provider cost fields are benchmark-level estimates, not buyer production prices; provider discounts, caching, routing, regional deployment, and rate-limit behavior are not represented.")
    lines.append("- Open-weight models and hosted proprietary models may reflect different deployment economics; BFCL `Total Cost ($)` is useful for benchmark comparison but not a complete total-cost-of-ownership model.")
    lines.append("- Model versions and provider pricing can change after the leaderboard snapshot; the frozen metadata records leaderboard update and archive snapshot but does not verify live current availability.")
    lines.append("- These limitations especially affect Profile D, where the selected model is cost-dependent.")
    lines.append("")
    lines.append("## 8. Profile B Threshold Audit")
    lines.append("")
    lines.append("Individual failure counts across 109 models:")
    for name in [
        "Irrelevance Detection below 90%",
        "Relevance Detection below 85%",
        "Multi Turn Miss Func below 70%",
        "Latency 95th Percentile above 60 seconds",
        "missing required safety-related fields",
    ]:
        lines.append(f"- {name}: {threshold_counts.get(name, 0)}")
    lines.append("")
    lines.append("Failure combinations:")
    for combo, count in threshold_combos.most_common():
        label = "no failures" if not combo else " + ".join(combo)
        lines.append(f"- {count}: {label}")
    lines.append("")
    lines.append("Profile B's zero-eligible result is primarily driven by the `Multi Turn Miss Func below 70%` threshold, which individually fails 106 of 109 models. The remaining models that pass that threshold still fail one or more hallucination/relevance or latency thresholds, so the zero-eligible result is caused by the conjunction, with one dominant bottleneck.")
    lines.append("")
    lines.append("## 9. Procurement Plausibility From Frozen Metadata")
    lines.append("")
    lines.extend(
        md_table(
            procurement,
            [
                ("Profile", "profile_id"),
                ("Model", "model"),
                ("Organization", "organization"),
                ("License", "license"),
                ("Model Link", "model_link_present"),
                ("Model Date", "model_update_date_detected"),
                ("Leaderboard Updated", "leaderboard_last_updated"),
                ("BFCL Package", "bfcl_eval_package"),
                ("Commit", "bfcl_eval_commit"),
                ("Archive", "archive_snapshot"),
                ("Plausibility", "procurement_plausibility_from_snapshot_only"),
            ],
        )
    )
    lines.append("")
    lines.append("The profile-selected models remain plausible candidates only in the limited sense that they are present in the frozen BFCL snapshot with model links, organization/license fields, and reproducibility metadata. No live availability check was performed.")
    lines.append("")
    lines.append("## 10. Decision-Flip Materiality Table")
    lines.append("")
    lines.extend(
        md_table(
            material_table,
            [
                ("Profile", "profile"),
                ("Selected Model", "selected_model"),
                ("Survives Without Cost", "survive_without_cost"),
                ("Survives Without Latency", "survive_without_latency"),
                ("Capability-Only Flip", "survive_capability_only"),
                ("Operational Materiality", "large_enough"),
                ("Questionable Input Dependence", "questionable_input"),
            ],
        )
    )
    lines.append("")
    lines.append("## 11. Interpretation")
    lines.append("")
    lines.append("Profile A provides the strongest verified frame-audit evidence: a defensible workflow frame selects a different model than BFCL's published aggregate winner, and that difference survives removal of cost and latency. Profile D adds supporting but weaker evidence because its full-profile winner is cost-dependent and BFCL cost comparability is limited. Profile B is too strict to produce an eligible model, and Profile C does not flip.")
    lines.append("")
    lines.append("VERIFIED FRAME AUDIT PASS")
    AUDIT_REPORT.write_text("\n".join(lines) + "\n", encoding="utf-8")
    return "VERIFIED FRAME AUDIT PASS"


def main() -> int:
    baseline = read_csv(BASELINE)
    stored_profiles = read_csv(PROFILE_RESULTS)
    fix_stats = fix_sensitivity_outputs()
    verification = verify_profiles(baseline, stored_profiles)
    decomp = decomposition_rows(baseline, "A") + decomposition_rows(baseline, "D")
    loo = leave_one_factor_rows(baseline)
    threshold_counts, threshold_combos = profile_b_threshold_audit(baseline)
    procurement = procurement_rows(baseline)
    verdict = write_audit_report(baseline, verification, fix_stats, decomp, loo, threshold_counts, threshold_combos, procurement)
    print(verdict)
    print(AUDIT_REPORT)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
