# backend/tests/test_nl_parser.py — 자연어 파서 골든 + 휴리스틱 폴백
import pytest

from app.automation.nl_parser import parse_rule
from app.llm.heuristic import HeuristicProvider

GOLDEN = [
    (
        "출장 전날엔 저녁 일정 비워줘",
        "cal",
        "출장 전날이 되면",
        "18시 이후 일정이 있으면",
        "다른 날로 옮기자고 제안",
    ),
    (
        "뉴스레터는 모아서 저녁에 보여줘",
        "mail",
        "뉴스레터 메일 도착",
        None,
        "받은편지함 건너뛰고 18:30 다이제스트로",
    ),
    (
        "운동을 3일 거르면 산책 잡아줘",
        "life",
        "운동 기록 3일 연속 없음",
        "저녁에 빈 시간이 있으면",
        "30분 산책 블록 제안",
    ),
]


@pytest.mark.parametrize("text,cat,trig,cond,action", GOLDEN)
def test_golden_examples(text, cat, trig, cond, action):
    r = parse_rule(text)
    assert r.matched and r.cat == cat
    assert r.trigger == trig and r.cond == cond and r.action == action
    assert r.model == "example"


def test_heuristic_fallback_classifies_cat():
    # examples 미일치 → 휴리스틱(명시 provider 로 환경(Ollama 가동 여부) 무관 결정적)
    r = parse_rule("영수증 들어오면 자동으로 정리해줘", provider=HeuristicProvider())
    assert r.matched and r.cat == "life" and r.model == "heuristic"


def test_empty_input_not_matched():
    r = parse_rule("")  # 빈 입력은 LLM 호출 없이 미매칭
    assert not r.matched


class _FakeProvider:
    name = "fake"
    model = "fake-llm"

    def health(self):
        return {"reachable": True}

    def generate_json(self, prompt, schema=None):
        return {
            "name": "회의록 자동화",
            "cat": "cal",
            "trigger": "회의 종료",
            "cond": None,
            "action": "요약 작성",
            "confidence": 0.9,
        }

    def classify_capture(self, raw, context):  # pragma: no cover
        raise NotImplementedError


def test_llm_path_uses_provider_json():
    r = parse_rule("회의 끝나면 요약해줘", provider=_FakeProvider())
    assert r.matched and r.cat == "cal" and r.action == "요약 작성"
    assert r.model == "llm:fake-llm"


class _BrokenProvider(_FakeProvider):
    def generate_json(self, prompt, schema=None):
        raise RuntimeError("llm down")


def test_llm_exception_falls_back_to_heuristic():
    r = parse_rule("영수증 들어오면 정리해줘", provider=_BrokenProvider())
    assert r.matched and r.model == "heuristic"
