"""
Extra parsers for the judge reply. Use with tap.run(..., extra_parser=...).
Pick the one that matches your judge prompt, or implement your own (reply: str) -> Any.
Config can set extra_parser: "parse_deal_from_reply" (or "no_extra", "raw_reply"); get_parser(name) resolves it.
"""

import re
from typing import Any, Callable, List, Optional


def no_extra(reply: str) -> None:
    """No parsing; result.extra is always None. Use when you don't need structured extra."""
    return None


def parse_deal_from_reply(reply: str) -> Optional[List[int]]:
    """
    Look for a line 'Deal: A, B' in the judge reply; return [A, B] or None.
    Use when your judge outputs e.g. "Rating: N" and "Deal: 90, 10" (e.g. negotiation/split scenarios).
    """
    for line in reply.splitlines():
        if line.strip().upper().startswith("DEAL:"):
            rest = line.split(":", 1)[1].strip().upper()
            if "NONE" in rest and not re.findall(r"\d+", line):
                return None
            nums = re.findall(r"\d+", line)
            if len(nums) >= 2:
                return [int(nums[0]), int(nums[1])]
            return None
    return None


def raw_reply(reply: str) -> str:
    """Pass through the judge reply as-is. result.extra is the full reply string. Useful for debugging or custom parsing later."""
    return reply


# Registry for config-driven choice: extra_parser: "parse_deal_from_reply" in YAML → this callable.
EXTRA_PARSERS = {
    "no_extra": no_extra,
    "parse_deal_from_reply": parse_deal_from_reply,
    "raw_reply": raw_reply,
}


def get_parser(name: Optional[str]) -> Optional[Callable[[str], Any]]:
    """Resolve extra_parser from config. name is the YAML value (e.g. 'parse_deal_from_reply'); returns the callable or None."""
    if name is None or (isinstance(name, str) and not name.strip()):
        return None
    return EXTRA_PARSERS.get(name.strip()) if isinstance(name, str) else None
