"""
test_composite_prompt.py

build_composite_prompt() 및 관련 함수 테스트 (아르고스 작성)
"""

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

import pytest

_WORKSPACE = Path(os.environ.get("WORKSPACE_ROOT", "/home/jay/workspace"))
if str(_WORKSPACE) not in sys.path:
    sys.path.insert(0, str(_WORKSPACE))

import prompts.team_prompts as tp


class TestLoadLogicalTeamAgents:
    """_load_logical_team_agents() 테스트"""

    def setup_method(self):
        """각 테스트 전 캐시 초기화"""
        tp._TEAM_AGENT_CACHE.clear()

    def test_loads_existing_json(self, tmp_path):
        """org-details JSON 파일이 존재하면 로드"""
        team_data = {
            "team_id": "marketing-team",
            "members_detail": {"apollo": {"name": "아폴론", "role": "콘텐츠 크리에이터"}},
        }
        detail_dir = tmp_path / "memory" / "org-details"
        detail_dir.mkdir(parents=True)
        (detail_dir / "marketing-team.json").write_text(json.dumps(team_data), encoding="utf-8")

        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)):
            result = tp._load_logical_team_agents("marketing")
            assert "members_detail" in result
            assert "apollo" in result["members_detail"]

    def test_caches_result(self, tmp_path):
        """같은 팀을 두 번 로드하면 캐시에서 반환"""
        team_data = {"team_id": "design-team", "members_detail": {}}
        detail_dir = tmp_path / "memory" / "org-details"
        detail_dir.mkdir(parents=True)
        (detail_dir / "design-team.json").write_text(json.dumps(team_data), encoding="utf-8")

        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)):
            result1 = tp._load_logical_team_agents("design")
            result2 = tp._load_logical_team_agents("design")
            assert result1 is result2  # 동일 객체 참조 (캐시)

    def test_fallback_to_team_info(self, tmp_path):
        """JSON 파일이 없으면 TEAM_INFO에서 members 문자열 사용"""
        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)):
            result = tp._load_logical_team_agents("marketing")
            assert "members" in result


class TestBuildCompositePrompt:
    """build_composite_prompt() 테스트"""

    def setup_method(self):
        tp._TEAM_AGENT_CACHE.clear()

    def test_defense_in_depth_invalid_team(self):
        """허용되지 않은 팀 ID → ValueError"""
        with pytest.raises(ValueError, match="허용되지 않은 팀 ID"):
            tp.build_composite_prompt(["marketing", "invalid"], "task-1.1", "test desc")

    def test_defense_in_depth_single_team(self):
        """2개 미만 팀 → ValueError"""
        with pytest.raises(ValueError, match="2개 이상"):
            tp.build_composite_prompt(["marketing"], "task-1.1", "test desc")

    def test_two_teams_prompt_generation(self, tmp_path):
        """2팀 조합 프롬프트 정상 생성"""
        mock_agents = {
            "members_detail": {
                "agent1": {"name": "Agent1", "role": "Role1", "model": "sonnet"},
            }
        }
        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)), \
             patch.object(tp, "_load_logical_team_agents", return_value=mock_agents):
            (tmp_path / "memory" / "tasks").mkdir(parents=True, exist_ok=True)
            prompt = tp.build_composite_prompt(
                ["marketing", "design"], "task-test.1", "테스트 작업"
            )
            assert "임시팀장" in prompt
            assert "task-test.1" in prompt
            assert "marketing" in prompt
            assert "design" in prompt

    def test_critical_level_header(self, tmp_path):
        """critical 레벨 → 헤더 포함"""
        mock_agents = {"members_detail": {}}
        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)), \
             patch.object(tp, "_load_logical_team_agents", return_value=mock_agents):
            (tmp_path / "memory" / "tasks").mkdir(parents=True, exist_ok=True)
            prompt = tp.build_composite_prompt(
                ["marketing", "design"], "task-test.1", "test", level="critical"
            )
            assert "[CRITICAL]" in prompt

    def test_security_level_header(self, tmp_path):
        """security 레벨 → 헤더 포함"""
        mock_agents = {"members_detail": {}}
        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)), \
             patch.object(tp, "_load_logical_team_agents", return_value=mock_agents):
            (tmp_path / "memory" / "tasks").mkdir(parents=True, exist_ok=True)
            prompt = tp.build_composite_prompt(
                ["marketing", "design"], "task-test.1", "test", level="security"
            )
            assert "[SECURITY]" in prompt

    def test_handoff_fields_dynamic(self, tmp_path):
        """marketing+design 조합 → 전용 핸드오프 필드"""
        mock_agents = {"members_detail": {}}
        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)), \
             patch.object(tp, "_load_logical_team_agents", return_value=mock_agents):
            (tmp_path / "memory" / "tasks").mkdir(parents=True, exist_ok=True)
            prompt = tp.build_composite_prompt(
                ["marketing", "design"], "task-test.1", "test"
            )
            assert "톤앤매너" in prompt
            assert "CTA 문구" in prompt

    def test_default_handoff_fields_for_three_teams(self, tmp_path):
        """3팀 조합 → DEFAULT_HANDOFF_FIELDS 사용"""
        mock_agents = {"members_detail": {}}
        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)), \
             patch.object(tp, "_load_logical_team_agents", return_value=mock_agents):
            (tmp_path / "memory" / "tasks").mkdir(parents=True, exist_ok=True)
            prompt = tp.build_composite_prompt(
                ["marketing", "design", "consulting"], "task-test.1", "test"
            )
            assert "핵심 결정사항" in prompt

    def test_prompt_contains_all_sections(self, tmp_path):
        """프롬프트에 9개 섹션 키워드 포함"""
        mock_agents = {"members_detail": {}}
        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)), \
             patch.object(tp, "_load_logical_team_agents", return_value=mock_agents):
            (tmp_path / "memory" / "tasks").mkdir(parents=True, exist_ok=True)
            prompt = tp.build_composite_prompt(
                ["marketing", "design"], "task-test.1", "test"
            )
            assert "작업 지시" in prompt
            assert "팀별 에이전트" in prompt
            assert "Phase 관리 프로토콜" in prompt
            assert "핸드오프 규격" in prompt
            assert "Quality Gate" in prompt
            assert "보고서 규칙" in prompt
            assert "토큰 관리" in prompt
            assert "완료 마무리" in prompt
            assert "finish-task.sh" in prompt

    def test_task_file_created(self, tmp_path):
        """task_desc가 파일로 저장됨"""
        mock_agents = {"members_detail": {}}
        with patch.object(tp, "WORKSPACE_ROOT", str(tmp_path)), \
             patch.object(tp, "_load_logical_team_agents", return_value=mock_agents):
            (tmp_path / "memory" / "tasks").mkdir(parents=True, exist_ok=True)
            tp.build_composite_prompt(
                ["marketing", "design"], "task-test.1", "테스트 작업 내용"
            )
            task_file = tmp_path / "memory" / "tasks" / "task-test.1.md"
            assert task_file.exists()
            assert task_file.read_text(encoding="utf-8") == "테스트 작업 내용"


class TestAssembleCompositePrompt:
    """_assemble_composite_prompt() 내부 함수 테스트"""

    def test_agents_with_dict_members(self):
        """members_detail이 dict인 경우 에이전트 목록 생성"""
        team_agents = {
            "marketing": {
                "members_detail": {
                    "apollo": {"name": "아폴론", "role": "콘텐츠", "model": "haiku", "mapped_skill": "content-strategy"},
                }
            },
            "design": {
                "members_detail": {
                    "benzaiten": {"name": "벤자이텐", "role": "템플릿", "model": "sonnet", "mapped_skill": "satori-cardnews"},
                }
            },
        }
        prompt = tp._assemble_composite_prompt(
            ["marketing", "design"], team_agents, ["톤앤매너"],
            "task-1.1", "/tmp/task.md", "normal", None,
        )
        assert "아폴론" in prompt
        assert "벤자이텐" in prompt
        assert "content-strategy" in prompt
        assert "satori-cardnews" in prompt

    def test_agents_with_string_members(self):
        """members가 문자열인 경우 (fallback)"""
        team_agents = {
            "marketing": {"members": "아폴론, 페이토, 에이레네"},
            "design": {"members": "벤자이텐, 비너스"},
        }
        prompt = tp._assemble_composite_prompt(
            ["marketing", "design"], team_agents, ["톤앤매너"],
            "task-1.1", "/tmp/task.md", "normal", None,
        )
        assert "아폴론, 페이토, 에이레네" in prompt
