"""Shared paths + cleaning helpers for the RU-CPT corpus pipeline.

The mixed-script / Cyrillic-cleanliness rule lives here ONCE and is reused by
corpus_clean.py, corpus_synth.py, and eval_cyrillic.py. See
docs/plans/2026-07-11-ru-cpt-base.md (§2.3 rule 3) in the Maven repo.

Run `python corpus_common.py` for a self-check of the mixed-script detector.
"""
import os
import re
from pathlib import Path

# ── env / cache (mirror train_rocm.py) ──────────────────────────────────────
os.environ.setdefault("HF_HOME", "/mnt/D/.cache/huggingface")
os.environ.setdefault("HF_DATASETS_CACHE", "/mnt/D/.cache/huggingface/datasets")
os.environ.setdefault("TMPDIR", "/mnt/D/tmp")
os.makedirs(os.environ["TMPDIR"], exist_ok=True)

# ── corpus dir layout ───────────────────────────────────────────────────────
DATA = Path(__file__).resolve().parent / "data"
RAW = DATA / "cpt_raw"        # corpus_fetch.py / corpus_synth.py output
CLEAN = DATA / "cpt_clean"    # corpus_clean.py output (JSONL {"text":...})
PACKED = DATA / "cpt_packed"  # corpus_pack.py output (HF Arrow, 2048-tok blocks)
for d in (RAW, CLEAN, PACKED):
    d.mkdir(parents=True, exist_ok=True)

# ── the corpus mix (plan §2.1) — bucket -> target token share ───────────────
TARGET_TOKENS = 300_000_000
BUCKET_SHARE = {          # sums to 1.0; synth capped at 0.10 (hard rule)
    "culturax": 0.60,
    "wiki": 0.17,
    "books": 0.11,
    "synth": 0.10,
    "logs": 0.02,
}
SYNTH_CAP = 0.10

# ── Cyrillic cleanliness (plan §2.3 rule 3) ─────────────────────────────────
_WORD = re.compile(r"[^\s]+")
_CYR = re.compile(r"[а-яёА-ЯЁ]")
_LAT = re.compile(r"[a-zA-Z]")


def is_mixed_script_word(word: str) -> bool:
    """True if a single token mixes Cyrillic and Latin letters (homoglyph swap)."""
    return bool(_CYR.search(word) and _LAT.search(word))


def has_mixed_script(text: str) -> bool:
    """True if ANY word in the text is homoglyph-contaminated."""
    return any(is_mixed_script_word(w) for w in _WORD.findall(text))


def cyrillic_ratio(text: str) -> float:
    """Fraction of letters that are Cyrillic (0..1). Empty/letterless -> 0."""
    cyr = len(_CYR.findall(text))
    lat = len(_LAT.findall(text))
    tot = cyr + lat
    return cyr / tot if tot else 0.0


# ── fastText language id (lazy singleton; download lid.176.bin, plan §2.3) ──
_LID = None
LID_PATH = os.environ.get("FASTTEXT_LID", str(DATA / "lid.176.bin"))


def lang_prob(text: str):
    """Return (lang_code, prob) for the dominant language, or (None, 0.0)."""
    global _LID
    if _LID is None:
        import fasttext
        if not Path(LID_PATH).exists():
            raise FileNotFoundError(
                f"fastText lid.176.bin not found at {LID_PATH}. Download from "
                "https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin "
                "or set FASTTEXT_LID env var."
            )
        # numpy 2.x compat: fasttext uses np.array(..., copy=False) which
        # raises on numpy >=2 when a copy is needed. patch its np reference.
        _orig_np_array = fasttext.FastText.np.array
        def _patched_array(*args, **kwargs):
            kwargs.pop("copy", None)
            return _orig_np_array(*args, **kwargs)
        fasttext.FastText.np.array = _patched_array
        _LID = fasttext.load_model(LID_PATH)
    labels, probs = _LID.predict(text.replace("\n", " ")[:2000])
    return labels[0].replace("__label__", ""), float(probs[0])


if __name__ == "__main__":
    # self-check: the homoglyph detector is the whole point — assert it works.
    assert is_mixed_script_word("privет")          # latin+cyrillic in one word
    assert is_mixed_script_word("Марkет")           # cyrillic 'Мар' + latin 'k'
    assert not is_mixed_script_word("привет")       # pure cyrillic
    assert not is_mixed_script_word("hello")        # pure latin
    assert not is_mixed_script_word("http://x.ru")  # pure latin url — keep
    assert has_mixed_script("это Марkет здесь")
    assert not has_mixed_script("это чистый русский текст with english words")
    assert abs(cyrillic_ratio("привет hello") - 0.5) < 0.05
    print("corpus_common self-check OK ->", DATA)
