"""Permanent test suite for economy-mode hook.

Tests via subprocess to verify end-to-end behavior including stdin
encoding, regex parsing, discussion-context filtering, and multi-match
handling. Run with: python ~/.claude/hooks/economy-mode-test.py

Exit code 0 = all green, 1 = any failure."""
import json
import os
import re
import subprocess
import sys

try:
    sys.stdout.reconfigure(encoding="utf-8")
except Exception:
    pass

SCRIPT = os.path.expanduser("~/.claude/hooks/economy-mode.py")


def parse_level(prompt):
    """Run hook with given prompt. Return:
    - int 0-100 if explicit activation
    - None if default (no keyword matched, or matched in discussion context)
    """
    payload = json.dumps({"prompt": prompt}, ensure_ascii=False).encode("utf-8")
    r = subprocess.run(
        ["python", SCRIPT],
        input=payload,
        capture_output=True,
        timeout=10,
    )
    if not r.stdout:
        return None
    try:
        d = json.loads(r.stdout.decode("utf-8"))
        ctx = d["hookSpecificOutput"]["additionalContext"]
    except Exception:
        return None
    # "(default" or "не указал уровень" both indicate non-explicit
    if "не указал уровень" in ctx or "(default" in ctx:
        return None
    m = re.search(r"ECONOMY MODE: (\d+)%", ctx)
    return int(m.group(1)) if m else None


# (prompt, expected_level_or_None, description)
TESTS = [
    # --- Russian inflection: ALL forms must activate ---
    ("экономия 75%", 75, "Nominative"),
    ("экономии 75%", 75, "Genitive"),
    ("экономию 75%", 75, "Accusative"),
    ("экономией 75%", 75, "Instrumental"),
    ("экономиями 75%", 75, "Plural instrumental"),
    ("Экономия 75%", 75, "Capitalized"),
    ("ЭКОНОМИЯ 75%", 75, "All caps"),

    # --- Separators: must accept space, colon, dash, em-dash, equals, comma, parens ---
    ("экономия 75%", 75, "Space sep"),
    ("экономия: 75%", 75, "Colon sep"),
    ("экономия - 75%", 75, "Hyphen sep"),
    ("экономия — 75%", 75, "Em-dash sep"),
    ("экономия = 75%", 75, "Equals sep"),
    ("экономия,75%", 75, "Comma sep"),
    ("экономия75%", 75, "No sep (digit right after)"),
    ("экономия (75%)", 75, "Parens"),

    # --- Numbers: integer, decimal, with/without space before % ---
    ("экономия 0%", 0, "Zero"),
    ("экономия 100%", 100, "Hundred"),
    ("экономия 75 %", 75, "Space before %"),
    ("экономия 75.5%", 75, "Decimal point"),
    ("экономия 75,5%", 75, "Decimal comma"),
    ("экономия 75.0%", 75, "Trailing .0"),
    ("экономия 0.0%", 0, "0.0"),
    ("экономия 200%", 100, "Out of range — clamp 100"),

    # --- Word boundary: must NOT match when preceded by word char ---
    ("1экономия 75%", None, "Preceded by digit"),
    ("пэкономия 75%", None, "Preceded by Cyrillic letter"),

    # --- Discussion contexts: must NOT activate ---
    ("как работает экономия 75%?", None, "Question with ?"),
    ("что даст экономия 75%", None, "'что даст' prefix"),
    ("что покрывает экономия 0%", None, "'что покрывает' prefix"),
    ("что такое экономия 75%", None, "'что такое' prefix"),
    ("не активируй экономия 75%", None, "Negation 'не'"),
    ("забудь про экономия 75%", None, "'забудь' prefix"),
    ("отбой экономия 75%", None, "'отбой' prefix"),
    ("пример: экономия 75%", None, "'пример' prefix"),

    # --- Multi-match: last non-discussion match wins ---
    ("экономия 75%, потом экономия 0%", 0, "Last match wins"),
    ("не экономия 75%, а экономия 0%", 0, "Skip negated first, take last"),
    ("экономия 75% (передумал) экономия 0%", 0, "Mid-prompt change"),

    # --- User's actual command from this turn ---
    (
        "тестирую все и снести изменения в хук, что он должен делать "
        "при команде экономия 0% все для максимального результата и с "
        "максимальным свеобъемливающим качеством. экономия 0%",
        0,
        "User's real command (this turn)",
    ),

    # --- Empty / edge cases ---
    ("", None, "Empty"),
    ("   ", None, "Whitespace only"),
    ("просто задача без ключа", None, "No keyword"),
    ("экономия %", None, "Missing number"),
    ("75%", None, "Missing keyword"),

    # === END-OF-PROMPT contract (NEW in v3) ===
    ("задача X. экономия 75%", 75, "Trailer style at end"),
    ("задача X. экономия 75%.", 75, "End with trailing period"),
    ("задача X. экономия 75%!", 75, "End with exclamation"),
    ("задача X. экономия 75% ", 75, "End with trailing whitespace"),
    ("делай X.\nэкономия 75%", 75, "Trailer on separate last line"),
    ("экономия 75% делай задачу X", None, "Pattern in middle, content after"),
    ("экономия 75% (срочно) делай X", None, "Pattern in middle with parens"),
    ("при команде экономия 75% что-то делать", None, "Pattern in middle of description"),
    ("экономия 75% потом экономия 0%", 0, "Last is at end"),
    ("экономия 0% (передумал) экономия 75% работать", None, "Last not at end"),

    # === Subset of v2 tests revisited ===
    ("экономия 75%, потом экономия 0%", 0, "Last wins (still applies)"),
    ("не экономия 75%, а экономия 0%", 0, "Last is at end after negation"),

    # === NEW: economy level 5% (якорь между 25 и 0) ===
    ("экономия 5%", 5, "Level 5 — exact anchor"),
    ("задача X. экономия 5%", 5, "Level 5 — end-of-prompt trailer"),
    ("экономия 5%.", 5, "Level 5 — trailing period"),
    ("экономия 10%", 5, "10% -> anchor 5 (раньше было 0)"),
    ("экономия 3%", 5, "3% -> 5 (нижняя кромка полосы)"),
    ("экономия 14%", 5, "14% -> 5 (верхняя кромка полосы)"),
    ("экономия 2%", 0, "2% -> 0 (чуть ниже полосы 5)"),
    ("экономия 15%", 25, "15% -> 25 (tie 5<->25, первый по порядку итерации)"),
]


def main() -> int:
    passed, failed, failures = 0, 0, []
    for prompt, expected, desc in TESTS:
        actual = parse_level(prompt)
        ok = actual == expected
        status = "PASS" if ok else "FAIL"
        # Ascii-safe printing for prompt (truncate)
        short = (prompt[:60] + "...") if len(prompt) > 60 else prompt
        print(f"  [{status}] {desc:40s} | exp={expected!s:5s} got={actual!s:5s} | {short!r}")
        if ok:
            passed += 1
        else:
            failed += 1
            failures.append((desc, prompt, expected, actual))

    print(f"\n=== {passed}/{passed+failed} PASSED, {failed} FAILED ===")
    if failures:
        print("\nFailures detail:")
        for desc, prompt, exp, got in failures:
            print(f"  {desc}: expected={exp}, got={got}")
            print(f"    prompt={prompt!r}")
    return 0 if failed == 0 else 1


if __name__ == "__main__":
    sys.exit(main())
