"""B-4 — licensed_restricted 차단 술어 + watch 타깃 (material/jurisdiction/license) 매핑 순수 테스트.

차단 술어(_license_sql)는 retrieval 3-leg + digest 가 공유하는 단일 술어. 실제 제외 동작은
GPU 라이브(합성 restricted doc 검색 제외)로 검증 — 여기선 술어 형태 + 매핑 표 계약만.
[[feedback_external_api_fixture_first]] / [[feedback_structural_integrity_over_path_discipline]]
"""

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent / "app"))

from services.search.license_filter import (  # noqa: E402
    restricted_exclude_orm,
    restricted_exclude_sql,
)
from services.search.retrieval_service import _license_sql  # noqa: E402
from workers.file_watcher import _TARGET_AXIS  # noqa: E402


def test_shared_predicate_single_source():
    # retrieval/digest/briefing 가 같은 술어 정의를 공유 — drift 방지(단일 source 계약)
    assert _license_sql("d") == " AND " + restricted_exclude_sql("d")
    assert _license_sql("") == " AND " + restricted_exclude_sql("")
    assert restricted_exclude_sql("d").startswith("COALESCE(d.extract_meta")


def test_restricted_exclude_orm_constructs():
    # study 풀이(explanation_rag)용 ORM 표현 — 컴파일 SQL 이 raw 술어와 동일 구조인지
    from sqlalchemy.dialects import postgresql

    clause = restricted_exclude_orm()
    sql = str(clause.compile(dialect=postgresql.dialect(),
                             compile_kwargs={"literal_binds": True}))
    assert "extract_meta" in sql
    assert "'license'" in sql and "'restricted'" in sql  # JSONB 경로 키
    assert "'false'" in sql and "'true'" in sql           # COALESCE 기본 + 비교값


def test_license_sql_shape_with_alias():
    sql = _license_sql("d")
    assert sql.startswith(" AND ")                       # 항상 ' AND ...' (WHERE 합성용)
    assert "COALESCE(d.extract_meta -> 'license' ->> 'restricted', 'false')" in sql
    assert "<> 'true'" in sql                            # restricted=true 만 제외


def test_license_sql_shape_no_alias():
    # alias='' = 단일 FROM documents (컬럼 직접 참조)
    sql = _license_sql("")
    assert "COALESCE(extract_meta -> 'license' ->> 'restricted', 'false')" in sql
    assert ".extract_meta" not in sql                    # 점 없는 컬럼 직접


def test_axis_books_papers_are_restricted():
    for folder, mt in (("Books", "book"), ("Papers_Purchased", "paper")):
        material, jur, lic = _TARGET_AXIS[folder]
        assert material == mt
        assert jur is None                               # 책/논문 = 관할 없음(A-2 paper NULL 강제와 정합)
        assert lic["scheme"] == "proprietary"
        assert lic["restricted"] is True                 # RAG/digest 차단 대상
        assert lic["redistribute"] is False


def test_axis_manuals_proprietary_but_not_restricted():
    material, jur, lic = _TARGET_AXIS["Manuals"]
    assert material == "manual"
    assert lic["scheme"] == "proprietary"
    assert lic["restricted"] is False                    # 사용자 결정 2026-06-13 (검색·RAG 활용)


def test_axis_kgs_law_kr_public_not_restricted():
    material, jur, lic = _TARGET_AXIS["KGS_Code"]
    assert (material, jur) == ("law", "KR")
    assert lic["scheme"] == "kogl"
    assert lic["restricted"] is False                    # 법정 위임 공공 → 차단 아님


def test_axis_non_target_folder_yields_none():
    # Inbox/Recordings 등 비대상 = (None, None, None) → material/license 미주입
    assert _TARGET_AXIS.get("Inbox", (None, None, None)) == (None, None, None)
