"""
NULLSIGHT -- provided baseline.  It is deliberately bad.

Classic first-generation DGA heuristic: Shannon entropy of the hostname over
a fixed threshold.  It was state of the art in about 2012 and it will not get
you a flag.  Understand why it fails before you replace it.

Run it locally against the sample round:

    NULLSIGHT_TRAIN=sample/train.csv \
    NULLSIGHT_TEST=sample/test.csv \
    NULLSIGHT_OUT=predictions.csv python baseline_solution.py
    python score_local.py predictions.csv sample/test_labels.csv
"""

from __future__ import annotations

import math
import os
from collections import Counter

import pandas as pd

TRAIN = os.environ.get("NULLSIGHT_TRAIN", "/data/train.csv")
TEST = os.environ.get("NULLSIGHT_TEST", "/data/test.csv")
OUT = os.environ.get("NULLSIGHT_OUT", "/out/predictions.csv")


def entropy(s: str) -> float:
    if not s:
        return 0.0
    c = Counter(s)
    n = len(s)
    return -sum((v / n) * math.log2(v / n) for v in c.values())


def main():
    train = pd.read_csv(TRAIN)
    test = pd.read_csv(TEST)

    # "tune" the threshold on the training set, such as it is
    best_t, best_acc = 3.0, 0.0
    ent_tr = train["domain"].astype(str).map(entropy)
    for t in [x / 10 for x in range(20, 50)]:
        acc = ((ent_tr > t).astype(int) == train["label"]).mean()
        if acc > best_acc:
            best_t, best_acc = t, acc

    pred = (test["domain"].astype(str).map(entropy) > best_t).astype(int)

    os.makedirs(os.path.dirname(OUT) or ".", exist_ok=True)
    pd.DataFrame({"id": test["id"], "label": pred}).to_csv(OUT, index=False)


if __name__ == "__main__":
    main()
