"""task-2478: blast_radius_parser 단위 테스트 — 카마소츠/모리건."""

from __future__ import annotations

import sys
from pathlib import Path

_WS_ROOT = Path(__file__).resolve().parents[2]
if str(_WS_ROOT) not in sys.path:
    sys.path.insert(0, str(_WS_ROOT))

from utils.blast_radius_parser import parse_blast_radius  # type: ignore[import-not-found]  # noqa: E402


class TestParseBlastRadius:
    """list/dict 양쪽 입력에 대한 parser 동작 검증."""

    def test_single_dict_with_blast_radius_key(self):
        """단일 파일 출력 (dict + blast_radius 중첩)."""
        data = {
            "changed_file": "src/foo.py",
            "blast_radius": {
                "direct_importers": ["src/baz.py"],
                "test_files": ["tests/test_foo.py"],
            },
        }
        di, tf = parse_blast_radius(data)
        assert di == ["src/baz.py"]
        assert tf == ["tests/test_foo.py"]

    def test_list_input_aggregates_all_items(self):
        """다파일 출력 (list) — 모든 항목 집계, .get() 호출 시 AttributeError 없음."""
        data = [
            {"changed_file": "a.py", "blast_radius": {"direct_importers": ["x.py"], "test_files": ["t1.py"]}},
            {"changed_file": "b.py", "blast_radius": {"direct_importers": ["y.py"], "test_files": ["t2.py"]}},
        ]
        di, tf = parse_blast_radius(data)
        assert di == ["x.py", "y.py"]
        assert tf == ["t1.py", "t2.py"]

    def test_list_dedupes_duplicates(self):
        """list 입력 시 중복 제거 + 입력 순서 유지."""
        data = [
            {"blast_radius": {"direct_importers": ["x.py", "y.py"], "test_files": []}},
            {"blast_radius": {"direct_importers": ["y.py", "z.py"], "test_files": []}},
        ]
        di, tf = parse_blast_radius(data)
        assert di == ["x.py", "y.py", "z.py"]
        assert tf == []

    def test_legacy_flat_dict_schema(self):
        """legacy 평탄 dict (테스트 mock 호환): {"direct_importers": [...], "test_files": [...]}"""
        data = {"direct_importers": ["src/baz.py"], "test_files": ["tests/test_foo.py"]}
        di, tf = parse_blast_radius(data)
        assert di == ["src/baz.py"]
        assert tf == ["tests/test_foo.py"]

    def test_empty_list(self):
        """빈 list → 빈 tuple."""
        assert parse_blast_radius([]) == ([], [])

    def test_empty_dict(self):
        """빈 dict → 빈 tuple."""
        assert parse_blast_radius({}) == ([], [])

    def test_malformed_blast_radius_not_dict(self):
        """blast_radius 값이 dict가 아닐 때(예: list/str) → legacy 평탄 schema fallback."""
        data = {"blast_radius": "unexpected_string", "direct_importers": ["fallback.py"], "test_files": []}
        di, tf = parse_blast_radius(data)
        assert di == ["fallback.py"]
        assert tf == []

    def test_non_dict_items_in_list_skipped(self):
        """list 내 dict가 아닌 항목은 스킵."""
        data = [
            {"blast_radius": {"direct_importers": ["a.py"], "test_files": []}},
            "not a dict",
            123,
            None,
            {"blast_radius": {"direct_importers": ["b.py"], "test_files": []}},
        ]
        di, _ = parse_blast_radius(data)
        assert di == ["a.py", "b.py"]

    def test_none_values_safe(self):
        """direct_importers/test_files가 None이어도 안전 처리."""
        data = {"blast_radius": {"direct_importers": None, "test_files": None}}
        di, tf = parse_blast_radius(data)
        assert di == []
        assert tf == []

    def test_non_list_inner_values_ignored(self):
        """direct_importers/test_files가 list가 아니면 무시."""
        data = {"blast_radius": {"direct_importers": "x.py", "test_files": 42}}
        di, tf = parse_blast_radius(data)
        assert di == []
        assert tf == []
