"""Prompt rendering + policy_version hash 검증."""

from __future__ import annotations

import pytest

from policy import prompt_render
from policy.prompt_render import (
    KNOWN_4B_TASKS,
    KNOWN_26B_TASKS,
    policy_version,
    render_26b,
    render_4b,
)


ALL_4B_TASKS = sorted(KNOWN_4B_TASKS)
ALL_26B_TASKS = sorted(KNOWN_26B_TASKS)


@pytest.mark.parametrize("task", ALL_4B_TASKS)
def test_render_4b_basic(policy, task):
    rendered = render_4b(task, subject_domain="safety_reference", policy=policy)
    # placeholder 가 남아있지 않아야 함 (정책 주입된 것들)
    assert "{forbidden_block}" not in rendered
    assert "{subject_description}" not in rendered
    assert "{confidence_threshold}" not in rendered
    assert "{context_cap}" not in rendered
    # 실제 금지 섹션 텍스트 포함
    assert "4B 절대 금지" in rendered
    # 사용자 input placeholder 는 남아있어야 함 (이중 중괄호 → 단일로 이스케이프됨)
    # 단, render 시점 이후 .format() 으로 주입되므로 {filename} 같은 건 나중에 치환


@pytest.mark.parametrize("task", ALL_26B_TASKS)
def test_render_26b_basic(policy, task):
    rendered = render_26b(task, subject_domain="safety_reference", policy=policy)
    assert "{forbidden_block}" not in rendered
    assert "{subject_description}" not in rendered
    assert "4B 절대 금지" in rendered


def test_render_4b_rejects_26b_task(policy):
    with pytest.raises(ValueError):
        render_4b("p3c_deep_summary", subject_domain="msds", policy=policy)


def test_render_26b_rejects_4b_task(policy):
    with pytest.raises(ValueError):
        render_26b("p3a_short_summary", subject_domain="msds", policy=policy)


def test_render_uses_fallback_for_unknown_domain(policy):
    """unknown subject 도 fallback_domain.description 이 사용되어 렌더 성공."""
    rendered = render_4b("p1_triage", subject_domain="__unknown__", policy=policy)
    assert policy.fallback_domain.description in rendered


def test_render_different_domain_different_forbidden_block(policy):
    """도메인별로 forbidden 블록 내용이 달라짐."""
    msds = render_4b("p3a_short_summary", subject_domain="msds", policy=policy)
    news = render_4b("p3a_short_summary", subject_domain="news_item", policy=policy)
    # msds 는 safety_sufficiency_assertion 규칙 포함
    assert "safety_sufficiency_assertion" in msds
    # news_item 은 news_multi_source_synthesis 규칙 포함
    assert "news_multi_source_synthesis" in news


# =====================================================================
# policy_version hash — deterministic
# =====================================================================


@pytest.mark.parametrize("task", ALL_4B_TASKS + ALL_26B_TASKS)
def test_policy_version_deterministic(policy_yaml_path, task):
    v1 = policy_version(task, policy_path=policy_yaml_path)
    v2 = policy_version(task, policy_path=policy_yaml_path)
    assert v1 == v2


def test_policy_version_length(policy_yaml_path):
    v = policy_version("p3a_short_summary", policy_path=policy_yaml_path)
    assert len(v) == 12
    # hex 문자열인지 확인
    int(v, 16)  # raises ValueError if not hex


def test_policy_version_differs_across_tasks(policy_yaml_path):
    v_a = policy_version("p1_triage", policy_path=policy_yaml_path)
    v_b = policy_version("p3a_short_summary", policy_path=policy_yaml_path)
    assert v_a != v_b, "다른 template 은 다른 hash 가 나와야 함"


def test_policy_version_changes_when_yaml_changes(tmp_path, policy_yaml_path):
    """yaml 을 바꾸면 hash 가 변한다."""
    original = policy_version("p3a_short_summary", policy_path=policy_yaml_path)

    # yaml 복사본 수정
    modified = tmp_path / "modified.yaml"
    from pathlib import Path

    original_text = Path(policy_yaml_path).read_text(encoding="utf-8")
    # 주석 한 줄 추가 — 구조 유지하면서 bytes 만 변경
    modified.write_text(original_text + "\n# test modification\n", encoding="utf-8")

    prompt_render.clear_cache()
    changed = policy_version("p3a_short_summary", policy_path=str(modified))
    assert original != changed, "yaml 바뀌면 hash 도 바뀌어야 함"
