"""task-2478: pr-open 경로 blast_radius list 입력 회귀 테스트 — 모리건.

worktree_manager._get_blast_radius_summary가 ast_dependency_map의 list 출력을
받았을 때 'list' object has no attribute 'get' 오류로 죽지 않는지 검증.
"""

from __future__ import annotations

import json
import sys
from pathlib import Path
from unittest.mock import MagicMock, patch

_WS_ROOT = Path(__file__).resolve().parents[2]
_SCRIPTS = _WS_ROOT / "scripts"
for p in (_WS_ROOT, _SCRIPTS):
    if str(p) not in sys.path:
        sys.path.insert(0, str(p))

from worktree_manager import _get_blast_radius_summary  # type: ignore[import-not-found]


def _make_proc(returncode: int = 0, stdout: str = "", stderr: str = "") -> MagicMock:
    m = MagicMock()
    m.returncode = returncode
    m.stdout = stdout
    m.stderr = stderr
    return m


class TestPrOpenBlastRadiusListInput:
    """ast_dependency_map list 출력 → AttributeError 무발생."""

    def test_list_input_does_not_raise_attribute_error(self):
        git_ok = _make_proc(returncode=0, stdout="src/foo.py\nsrc/bar.py\n")
        ast_list = [
            {"changed_file": "src/foo.py", "blast_radius": {
                "direct_importers": ["src/baz.py"],
                "test_files": ["tests/test_foo.py"],
                "callers": [], "transitive_dependents": [], "total_affected": 2,
            }},
            {"changed_file": "src/bar.py", "blast_radius": {
                "direct_importers": ["src/qux.py"],
                "test_files": ["tests/test_bar.py"],
                "callers": [], "transitive_dependents": [], "total_affected": 2,
            }},
        ]
        ast_ok = _make_proc(returncode=0, stdout=json.dumps(ast_list))
        with patch("subprocess.run", side_effect=[git_ok, ast_ok]):
            result = _get_blast_radius_summary("/fake/path", "feature", "main")
        # 핵심: AttributeError 없이 마크다운 반환
        assert result.startswith("## Blast Radius")
        assert "src/baz.py" in result
        assert "src/qux.py" in result
        assert "tests/test_foo.py" in result
        assert "tests/test_bar.py" in result

    def test_single_dict_with_blast_radius_nested(self):
        """단일 파일 ast 출력(dict + blast_radius 중첩) — 정상 처리."""
        git_ok = _make_proc(returncode=0, stdout="src/foo.py\n")
        ast_dict = {"changed_file": "src/foo.py", "blast_radius": {
            "direct_importers": ["src/baz.py"], "test_files": ["tests/test_foo.py"],
            "callers": [], "transitive_dependents": [], "total_affected": 1,
        }}
        ast_ok = _make_proc(returncode=0, stdout=json.dumps(ast_dict))
        with patch("subprocess.run", side_effect=[git_ok, ast_ok]):
            result = _get_blast_radius_summary("/fake/path", "feature", "main")
        assert result.startswith("## Blast Radius")
        assert "src/baz.py" in result

    def test_legacy_flat_dict_backward_compat(self):
        """legacy 평탄 dict(기존 test_ast_integration mock) — backward compat."""
        git_ok = _make_proc(returncode=0, stdout="src/foo.py\n")
        ast_legacy = {"direct_importers": ["src/baz.py"], "test_files": ["tests/test_foo.py"]}
        ast_ok = _make_proc(returncode=0, stdout=json.dumps(ast_legacy))
        with patch("subprocess.run", side_effect=[git_ok, ast_ok]):
            result = _get_blast_radius_summary("/fake/path", "feature", "main")
        assert result.startswith("## Blast Radius")
        assert "src/baz.py" in result

    def test_empty_list_returns_empty_summary(self):
        """빈 list → 빈 importers/tests로 마크다운 반환."""
        git_ok = _make_proc(returncode=0, stdout="src/foo.py\n")
        ast_ok = _make_proc(returncode=0, stdout=json.dumps([]))
        with patch("subprocess.run", side_effect=[git_ok, ast_ok]):
            result = _get_blast_radius_summary("/fake/path", "feature", "main")
        assert result.startswith("## Blast Radius")
        assert "없음" in result
