"""
Local scorer for the sample round.  Same metric and the same public/hidden
split logic the arena uses, so a number here means something.

    python score_local.py predictions.csv sample/test_labels.csv
"""

from __future__ import annotations

import sys

import pandas as pd
from sklearn.metrics import f1_score


def main(pred_path: str, labels_path: str) -> int:
    labels = pd.read_csv(labels_path)
    pred = pd.read_csv(pred_path)

    cols = {c.lower().strip(): c for c in pred.columns}
    if "id" not in cols or "label" not in cols:
        print(f"predictions must have columns id,label (got {list(pred.columns)})")
        return 2
    pred = pred[[cols["id"], cols["label"]]]
    pred.columns = ["id", "label"]
    pred = pred.drop_duplicates(subset="id", keep="last")

    merged = labels.merge(pred, on="id", how="left", suffixes=("", "_p"))
    missing = int(merged["label_p"].isna().sum())
    merged["label_p"] = merged["label_p"].fillna(0).round().clip(0, 1).astype(int)

    pub = merged[merged.is_public]
    prv = merged[~merged.is_public]
    print(f"rows            : {len(merged)}  (missing predictions: {missing})")
    print(f"public  macro-F1: {f1_score(pub.label, pub.label_p, average='macro'):.4f}"
          f"   [{len(pub)} rows -- this is what the leaderboard shows]")
    print(f"hidden  macro-F1: {f1_score(prv.label, prv.label_p, average='macro'):.4f}"
          f"   [{len(prv)} rows -- this is what the flag gate reads]")
    print()
    print("Reference points on this sample round:")
    print("  provided entropy baseline ~0.40")
    print("  char n-grams over the raw hostname, nothing else  ~0.89")
    print("  what the gate wants  ~0.93+")
    return 0


if __name__ == "__main__":
    if len(sys.argv) != 3:
        print(__doc__)
        raise SystemExit(1)
    raise SystemExit(main(sys.argv[1], sys.argv[2]))
