"""
팀별 프롬프트 생성 공통 모듈 (team_prompts.py)

dispatch.py와 orchestrator.py에서 공통으로 사용하는 프롬프트 생성 로직.
dev1-team/dev2-team(direct): Opus 팀장 직접 코딩
dev3-team(direct): 켈트 신화 팀, Opus 팀장 직접 코딩
dev4-team(direct): 비슈누 팀장, 직접 코딩
dev8-team(glm): 라 팀장, GLM-5 위임

Usage:
    from prompts.team_prompts import build_prompt, TEAM_INFO
    prompt = build_prompt("dev1-team", "task-1.1", "API 서버 개발")
"""

import json
import os
from pathlib import Path
from typing import List, Optional

WORKSPACE_ROOT = os.environ.get("WORKSPACE_ROOT", "/home/jay/workspace")
from config.loader import ConfigManager as _CfgMgr
from prompts.gate_instructions import format_for_prompt as _format_gate_instructions

_cfg_tp = _CfgMgr.get_instance()
CHAT_ID = os.environ.get("COKACDIR_CHAT_ID") or _cfg_tp.get_constant("chat_id")
ANU_KEY = os.environ.get("COKACDIR_KEY_ANU", "")
from utils.composite_constants import (  # type: ignore[reportMissingImports]
    COMPOSITE_ALLOWED_TEAMS,
    DEFAULT_HANDOFF_FIELDS,
    HANDOFF_REQUIRED_FIELDS,
)


def _get_anu_key() -> str:
    """ANU_KEY를 반환. 없으면 EnvironmentError (사용 시점 fail-fast)."""
    if not ANU_KEY:
        raise EnvironmentError("COKACDIR_KEY_ANU 환경변수가 설정되지 않았습니다.")
    return ANU_KEY


# 팀 정보 (canonical)
TEAM_INFO = {
    "dev1-team": {
        "leader": "헤르메스 (Hermes)",
        "role": "개발1팀장",
        "type": "direct",
        "members": "불칸(백엔드), 이리스(프론트엔드), 아테나(UX/UI), 아르고스(테스터)",
    },
    "dev2-team": {
        "leader": "오딘 (Odin)",
        "role": "개발2팀장",
        "type": "direct",
        "members": "토르(백엔드), 프레이야(프론트엔드), 미미르(UX/UI), 헤임달(테스터)",
    },
    "dev3-team": {
        "leader": "다그다 (Dagda)",
        "role": "개발3팀장",
        "type": "direct",
        "members": "루(Lugh, 백엔드), 브리짓(Brigid, 프론트엔드), 아네(Aine, UX/UI), 모리건(Morrigan, 테스터)",
    },
    "dev4-team": {
        "leader": "비슈누 (Vishnu)",
        "role": "개발4팀장",
        "type": "direct",
        "members": "카르티케야(백엔드), 사라스바티(프론트엔드), 락슈미(UX/UI), 하누만(테스터)",
    },
    "dev5-team": {
        "leader": "마르둑 (Marduk)",
        "role": "개발5팀장",
        "type": "direct",
        "members": "엔키(백엔드), 이쉬타르(프론트엔드), 나부(UX/UI), 닌기르수(테스터)",
    },
    "dev6-team": {
        "leader": "페룬 (Perun)",
        "role": "개발6팀장",
        "type": "direct",
        "members": "스바로그(백엔드), 라다(프론트엔드), 모코시(UX/UI), 벨레스(테스터)",
    },
    "dev7-team": {
        "leader": "이참나 (Itzamna)",
        "role": "개발7팀장",
        "type": "direct",
        "members": "쿠쿨칸(백엔드), 이쉬첼(프론트엔드), 아쿠인(UX/UI), 카마소츠(테스터)",
    },
    "dev8-team": {
        "leader": "라 (Ra)",
        "role": "개발8팀장",
        "type": "mcp",
        "members": "아누비스(백엔드), 호루스(프론트엔드), 바스테트(UX/UI), 소베크(테스터)",
    },
    "marketing": {
        "leader": "마케팅 팀장",
        "role": "마케팅 팀장",
        "type": "marketing",
        "members": "아폴론(콘텐츠 프로듀서/블로그 작성), 페이토(카피라이터), 에이레네(SEO & 리서치 전략가/블로그 발행)",
    },
    "consulting": {
        "leader": "컨설팅 팀장",
        "role": "컨설팅 팀장",
        "type": "consulting",
        "members": "아스클레피오스(보장분석/진단), 테미스(약관비교/규정 검토)",
    },
    "publishing": {
        "leader": "토트 (Thoth)",
        "role": "출판 센터장",
        "type": "publishing",
        "members": "칼리오페(구성/아웃라인), 에라토(초안), 클리오(팩트검증), 테르프시코레(퇴고/편집), 폴리뮤니아(마무리/카피), 세쉬아트(DOCX 편집)",
    },
    "design": {
        "leader": "아마테라스 (Amaterasu)",
        "role": "디자인 팀장",
        "type": "design",
        "members": "벤자이텐(템플릿 디자인), 이나리(하이브리드 이미지), 카구야(아트 디자인)",
    },
    "content": {
        "leader": "아폴론 (Apollo)",
        "role": "콘텐츠 팀 리드",
        "type": "content",
        "members": "아폴론(콘텐츠 프로듀서/팀 리드), 페이토(CRO 카피라이터/30% 겸임), 에이레네(SEO 자문), 벤자이텐(카드뉴스), 라타토스크(배포), 에코(데이터 수집)",
    },
}

# 팀원 역할별 상세 (코워크 섹션 동적 생성용)
TEAM_MEMBER_ROLES = {
    "dev1-team": [
        ("불칸", "백엔드", "백엔드 로직/API/데이터 처리"),
        ("이리스", "프론트엔드", "UI/프론트엔드 구현"),
        ("아테나", "UX/UI", "UX 설계 및 스타일/레이아웃"),
        ("아르고스", "테스터", "테스트 코드 작성 및 검증"),
    ],
    "dev2-team": [
        ("토르", "백엔드", "백엔드 로직/API/데이터 처리"),
        ("프레이야", "프론트엔드", "UI/프론트엔드 구현"),
        ("미미르", "UX/UI", "UX 설계 및 스타일/레이아웃"),
        ("헤임달", "테스터", "테스트 코드 작성 및 검증"),
    ],
    "dev3-team": [
        ("루", "백엔드", "백엔드 로직/API/데이터 처리"),
        ("브리짓", "프론트엔드", "UI/프론트엔드 구현"),
        ("아네", "UX/UI", "UX 설계 및 스타일/레이아웃"),
        ("모리건", "테스터", "테스트 코드 작성 및 검증"),
    ],
    "dev4-team": [
        ("카르티케야", "백엔드", "백엔드 로직/API/데이터 처리"),
        ("사라스바티", "프론트엔드", "UI/프론트엔드 구현"),
        ("락슈미", "UX/UI", "UX 설계 및 스타일/레이아웃"),
        ("하누만", "테스터", "테스트 코드 작성 및 검증"),
    ],
    "dev5-team": [
        ("엔키", "백엔드", "백엔드 로직/API/데이터 처리"),
        ("이쉬타르", "프론트엔드", "UI/프론트엔드 구현"),
        ("나부", "UX/UI", "UX 설계 및 스타일/레이아웃"),
        ("닌기르수", "테스터", "테스트 코드 작성 및 검증"),
    ],
    "dev6-team": [
        ("스바로그", "백엔드", "백엔드 로직/API/데이터 처리"),
        ("라다", "프론트엔드", "UI/프론트엔드 구현"),
        ("모코시", "UX/UI", "UX 설계 및 스타일/레이아웃"),
        ("벨레스", "테스터", "테스트 코드 작성 및 검증"),
    ],
    "dev7-team": [
        ("쿠쿨칸", "백엔드", "백엔드 로직/API/데이터 처리"),
        ("이쉬첼", "프론트엔드", "UI/프론트엔드 구현"),
        ("아쿠인", "UX/UI", "UX 설계 및 스타일/레이아웃"),
        ("카마소츠", "테스터", "테스트 코드 작성 및 검증"),
    ],
    "dev8-team": [
        ("아누비스", "백엔드", "백엔드 로직/API/데이터 처리"),
        ("호루스", "프론트엔드", "UI/프론트엔드 구현"),
        ("바스테트", "UX/UI", "UX 설계 및 스타일/레이아웃"),
        ("소베크", "테스터", "테스트 코드 작성 및 검증"),
    ],
}

# ── P2-5: 모델 매핑 테이블 ──────────────────────────────────────
MODEL_MAP = {
    "팀장": {"default": "opus", "설계": "opus"},
    "백엔드": {"default": "sonnet", "아키텍처": "opus"},
    "프론트엔드": {"default": "sonnet"},
    "UX/UI": {"default": "sonnet", "에셋생성": "haiku"},
    "테스터": {"default": "haiku", "테스트설계": "sonnet"},
    "QC": {"default": "haiku"},
    "git": {"default": "haiku"},
    "보안리뷰": {"default": "opus"},
    "_updated": "2026-03-31",
}


def _build_model_guide() -> str:
    """MODEL_MAP 기반 모델 가이드 텍스트 자동 생성."""
    import logging
    from datetime import datetime, timedelta

    lines = "[모델 가이드]\n"
    for role, config in MODEL_MAP.items():
        if role.startswith("_"):
            continue
        default_model = config.get("default", "sonnet")
        extras = {k: v for k, v in config.items() if k != "default"}
        if extras:
            extra_str = ", ".join(f"{k}: {v}" for k, v in extras.items())
            lines += f"- {role}: {default_model} ({extra_str})\n"
        else:
            lines += f"- {role}: {default_model}\n"

    # staleness 경고 (7일 초과 시)
    updated_str = MODEL_MAP.get("_updated", "")
    if updated_str:
        try:
            updated_date = datetime.strptime(str(updated_str), "%Y-%m-%d")
            days_elapsed = (datetime.now() - updated_date).days
            if days_elapsed > 7:
                logging.warning(
                    "[WARNING] MODEL_MAP이 %d일 경과했습니다. 최신 모델 정책을 확인하세요.",
                    days_elapsed,
                )
        except ValueError:
            pass

    return lines


_TEAM_AGENT_CACHE: dict = {}


def _load_logical_team_agents(team_id: str) -> dict:
    """org-details JSON에서 팀 에이전트 정보 로드 (캐시 포함).

    Args:
        team_id: 논리적 팀 ID (예: "marketing", "design")

    Returns:
        팀 에이전트 정보 딕셔너리
    """
    if team_id in _TEAM_AGENT_CACHE:
        return _TEAM_AGENT_CACHE[team_id]
    detail_path = Path(WORKSPACE_ROOT) / "memory" / "org-details" / f"{team_id}-team.json"
    if detail_path.exists():
        with open(detail_path, "r", encoding="utf-8") as f:
            result = json.load(f)
            _TEAM_AGENT_CACHE[team_id] = result
            return result
    # fallback: TEAM_INFO에서 members 문자열 사용
    fallback = {"members": TEAM_INFO.get(team_id, {}).get("members", "")}
    _TEAM_AGENT_CACHE[team_id] = fallback
    return fallback


def _build_project_map_section(project_id: Optional[str]) -> str:
    """project-map 파일이 존재하면 참조 경로 섹션 반환, 없으면 빈 문자열 반환"""
    if project_id is None:
        return ""
    map_path = Path(WORKSPACE_ROOT) / "memory" / "project-maps" / f"{project_id}.md"
    if not map_path.exists():
        return ""
    return (
        f"## 프로젝트 구조 맵\n"
        f"작업 시작 전 프로젝트 구조 맵을 먼저 읽고 작업을 시작하세요: {WORKSPACE_ROOT}/memory/project-maps/{project_id}.md\n\n"
    )


def _build_session_monitoring_section() -> str:
    """세션 토큰 모니터링 지시 섹션 생성.

    봇 세션이 길어질 때 자동 압축 및 요약/재시작을 안내한다.
    임계값은 constants.json의 session_monitoring 섹션에서 로드.
    """
    config_path = Path(WORKSPACE_ROOT) / "config" / "constants.json"
    try:
        with open(config_path, encoding="utf-8") as f:
            data = json.load(f)
        sm = data.get("session_monitoring", {})
    except (FileNotFoundError, json.JSONDecodeError, KeyError):
        sm = {}

    warning_pct = sm.get("warning_pct", 70)
    critical_pct = sm.get("critical_pct", 85)
    resume_pct = sm.get("resume_pct", 90)
    tool_threshold = sm.get("tool_call_compact_threshold", 50)
    time_minutes = sm.get("time_compact_minutes", 30)

    return (
        f"\n## 세션 모니터링 (자동 압축)\n"
        f"세션이 길어지면 아래 기준에 따라 대응하세요:\n"
        f"- **{warning_pct}% 도달**: `/compact` 실행하여 컨텍스트 압축\n"
        f"- **{critical_pct}% 도달**: 즉시 중간 체크포인트 저장 후 `/compact` 실행\n"
        f"- **{resume_pct}% 초과**: 세션 요약 파일 저장 → 새 세션에서 이어서 작업\n"
        f"  - 요약 저장: `{WORKSPACE_ROOT}/memory/sessions/summary-{{task_id}}-{{timestamp}}.md`\n"
        f"  - 요약 내용: 현재 진행 상태, 수정 파일 목록, 남은 작업, 에러 목록\n"
        f"- 관련 모듈: `{WORKSPACE_ROOT}/utils/session_auto_compress.py`\n"
        f"- 도구 {tool_threshold}회 호출 or {time_minutes}분 경과 시 `/compact` 실행 권장\n"
    )


# Used by: tests/test_team_prompts.py (external access)
def _build_cowork_section(team_id: str) -> str:
    """팀원 코워크 섹션 생성 (팀별 동적)"""
    members = TEAM_MEMBER_ROLES.get(team_id, [])
    lines = (
        f"## 팀원 코워크 (Task tool 사용)\n"
        f"Claude Code의 Task tool을 사용하여 팀원 역할을 병렬로 수행하세요.\n"
        f"작업을 서브태스크로 분해한 뒤, 독립적인 서브태스크는 단일 메시지에 여러 Task tool 호출로 병렬 실행합니다:\n"
    )
    for name, role, desc in members:
        lines += f"- **{name} ({role})**: subagent_type=general-purpose, {desc}\n"
    lines += (
        f"\n**★ 팀장 역할 원칙 (Opus 토큰 절감):**\n"
        f"- 팀장(Opus)은 직접 코딩하지 않는다. 설계/분배/검토/통합만 수행.\n"
        f"- 모든 코딩은 팀원(Sonnet/Haiku)에게 Task tool로 위임.\n"
        f"- Sonnet이 3회 실패한 경우에만 팀장이 직접 코딩 개입 허용.\n\n"
    )

    # P2-5: MODEL_MAP 기반 모델 가이드 (feature flag 분기)
    _ff_path = os.path.join(WORKSPACE_ROOT, ".claude", "feature_flags.json")
    _mm_enabled = False
    try:
        with open(_ff_path, "r", encoding="utf-8") as _f:
            _ff_data = json.load(_f)
        _mm_enabled = _ff_data.get("flags", {}).get("model_map_enabled", False)
    except (FileNotFoundError, json.JSONDecodeError):
        pass

    if _mm_enabled:
        lines += f"**{_build_model_guide()}**\n"
    else:
        lines += (
            f"**모델 선택 가이드:**\n"
            f'- 단순 코딩/유틸리티/테스트 → model="haiku" (비용 절감)\n'
            f'- 일반 코딩/로직 구현 → model="sonnet" (기본값, 대부분의 코딩)\n'
            f"- ⚠️ 팀장(Opus)이 직접 코딩하지 마세요.\n\n"
        )

    lines += (
        f"**마이크로태스크 분해 규칙 (Lv.2+ 작업):**\n"
        f"- 각 서브태스크를 2~5분 단위 마이크로태스크로 분해\n"
        f"- 각 마이크로태스크에 명시할 항목: (1) 대상 파일 (2) 변경 내용 (3) 테스트 방법 (4) 커밋 메시지\n"
        f"- 팀원에게 할당 시 마이크로태스크 단위로 분배\n"
        f"- Lv.1 단순 수정은 이미 파일/라인이 특정되므로 분해 불필요\n\n"
        f"**테스터 Evidence Collector 규칙:**\n"
        f"- 기본값 = NEEDS WORK. 증거로 뒤집어야 PASS\n"
        f"- Zero Issue = Red Flag (첫 구현에서 이슈 0건은 비현실적, 최소 3개 발견 필수)\n"
        f"- 스크린샷/로그 등 증거 필수 (browser.py 활용)\n"
        f"- 상세: {WORKSPACE_ROOT}/memory/specs/retry-escalation-protocol.md 참조\n\n"
    )
    return lines


def _build_marketing_prompt(
    team: dict,
    team_id: str,
    task_id: str,
    task_file_path: str,
    level: str,
    timer_start: str,
    timer_end: str,
    report_path: str,
    project_id: Optional[str] = None,
    chain_id: Optional[str] = None,
) -> str:
    """마케팅 팀 프롬프트 생성 (경량화: 파일 참조 패턴)"""
    _ = (team, level, timer_start, timer_end, project_id, chain_id)  # interface params
    team_short = team_id
    placeholder_lines = (
        f"- task_id: {task_id}\n"
        f"- team_id: {team_id}\n"
        f"- team_short: {team_short}\n"
        f"- WORKSPACE_ROOT: {WORKSPACE_ROOT}\n"
        f"- report_path: {report_path}\n"
    )
    return (
        f"당신은 마케팅 팀장입니다. 다음 마케팅 작업을 수행하세요.\n\n"
        f"## 작업 지시\n"
        f"- 작업 ID: {task_id}\n"
        f"- 작업 상세는 {task_file_path}를 읽고 파악하세요.\n\n"
        f"## 팀 구성 및 스킬\n"
        f"{WORKSPACE_ROOT}/prompts/teams/marketing.md를 읽고 파악하세요.\n\n"
        f"## 워크플로우\n"
        f"{WORKSPACE_ROOT}/prompts/LOGICAL-TEAM-WORKFLOW.md를 읽고 따르세요.\n"
        f"아래 값을 워크플로우에서 사용하세요:\n"
        f"{placeholder_lines}"
        f"\n## 서브에이전트(Task tool) 결과 규칙\n"
        f"- 상세 결과는 파일로 저장하고, Task tool 반환값은 요약만 포함 (500자 이내)\n"
        f"- 요약 필수 포함: 성공/실패 여부, FAIL 항목 수/코드/사유 (있는 경우), 산출물 파일 경로\n"
        f'"FAIL 존재 시 반드시 FAIL 코드와 사유를 요약에 포함"\n'
    )


def _build_consulting_prompt(
    team: dict,
    team_id: str,
    task_id: str,
    task_file_path: str,
    level: str,
    timer_start: str,
    timer_end: str,
    report_path: str,
    project_id: Optional[str] = None,
    chain_id: Optional[str] = None,
) -> str:
    """컨설팅 팀 프롬프트 생성 (경량화: 파일 참조 패턴)"""
    _ = (team, level, timer_start, timer_end, project_id, chain_id)  # interface params
    team_short = team_id
    placeholder_lines = (
        f"- task_id: {task_id}\n"
        f"- team_id: {team_id}\n"
        f"- team_short: {team_short}\n"
        f"- WORKSPACE_ROOT: {WORKSPACE_ROOT}\n"
        f"- report_path: {report_path}\n"
    )
    return (
        f"당신은 컨설팅 팀장입니다. 보험 컨설팅 관련 작업을 수행하세요.\n\n"
        f"## 작업 지시\n"
        f"- 작업 ID: {task_id}\n"
        f"- 작업 상세는 {task_file_path}를 읽고 파악하세요.\n\n"
        f"## 팀 구성 및 스킬\n"
        f"{WORKSPACE_ROOT}/prompts/teams/consulting.md를 읽고 파악하세요.\n\n"
        f"## 워크플로우\n"
        f"{WORKSPACE_ROOT}/prompts/LOGICAL-TEAM-WORKFLOW.md를 읽고 따르세요.\n"
        f"아래 값을 워크플로우에서 사용하세요:\n"
        f"{placeholder_lines}"
    )


def _build_publishing_prompt(
    team: dict,
    team_id: str,
    task_id: str,
    task_file_path: str,
    level: str,
    timer_start: str,
    timer_end: str,
    report_path: str,
    project_id: Optional[str] = None,
    chain_id: Optional[str] = None,
) -> str:
    """출판팀 프롬프트 생성 (경량화: 파일 참조 패턴)"""
    _ = (team, level, timer_start, timer_end, project_id, chain_id)  # interface params
    team_short = team_id
    placeholder_lines = (
        f"- task_id: {task_id}\n"
        f"- team_id: {team_id}\n"
        f"- team_short: {team_short}\n"
        f"- WORKSPACE_ROOT: {WORKSPACE_ROOT}\n"
        f"- report_path: {report_path}\n"
    )
    return (
        f"당신은 토트(Thoth), 출판 센터장입니다. 집필 프로젝트를 총괄하세요.\n\n"
        f"## 작업 지시\n"
        f"- 작업 ID: {task_id}\n"
        f"- 작업 상세는 {task_file_path}를 읽고 파악하세요.\n\n"
        f"## 팀 구성 및 스킬\n"
        f"{WORKSPACE_ROOT}/prompts/teams/publishing.md를 읽고 파악하세요.\n\n"
        f"## 워크플로우\n"
        f"{WORKSPACE_ROOT}/prompts/LOGICAL-TEAM-WORKFLOW.md를 읽고 따르세요.\n"
        f"아래 값을 워크플로우에서 사용하세요:\n"
        f"{placeholder_lines}"
    )


def _build_design_prompt(
    team: dict,
    team_id: str,
    task_id: str,
    task_file_path: str,
    level: str,
    timer_start: str,
    timer_end: str,
    report_path: str,
    project_id: Optional[str] = None,
    chain_id: Optional[str] = None,
) -> str:
    """디자인 팀 프롬프트 생성 (경량화: 파일 참조 패턴)"""
    _ = (team, level, timer_start, timer_end, project_id, chain_id)  # interface params
    team_short = team_id
    placeholder_lines = (
        f"- task_id: {task_id}\n"
        f"- team_id: {team_id}\n"
        f"- team_short: {team_short}\n"
        f"- WORKSPACE_ROOT: {WORKSPACE_ROOT}\n"
        f"- report_path: {report_path}\n"
    )
    return (
        f"당신은 아마테라스(Amaterasu), 디자인 팀장입니다. 이미지 생성 작업 전문팀을 이끌고 비주얼 디자인 작업을 수행하세요.\n\n"
        f"## 작업 지시\n"
        f"- 작업 ID: {task_id}\n"
        f"- 작업 상세는 {task_file_path}를 읽고 파악하세요.\n\n"
        f"## 팀 구성 및 스킬\n"
        f"{WORKSPACE_ROOT}/prompts/teams/design.md를 읽고 파악하세요.\n\n"
        f"## 워크플로우\n"
        f"{WORKSPACE_ROOT}/prompts/LOGICAL-TEAM-WORKFLOW.md를 읽고 따르세요.\n"
        f"아래 값을 워크플로우에서 사용하세요:\n"
        f"{placeholder_lines}"
        f"\n## 서브에이전트(Task tool) 결과 규칙\n"
        f"- 상세 결과는 파일로 저장하고, Task tool 반환값은 요약만 포함 (500자 이내)\n"
        f"- 요약 필수 포함: 성공/실패 여부, FAIL 항목 수/코드/사유 (있는 경우), 산출물 파일 경로\n"
        f'"FAIL 존재 시 반드시 FAIL 코드와 사유를 요약에 포함"\n'
    )


def _build_content_prompt(
    team: dict,
    team_id: str,
    task_id: str,
    task_file_path: str,
    level: str,
    timer_start: str,
    timer_end: str,
    report_path: str,
    project_id: Optional[str] = None,
    chain_id: Optional[str] = None,
) -> str:
    """콘텐츠 팀 프롬프트 생성 (경량화: 파일 참조 패턴)"""
    _ = (team, level, timer_start, timer_end, project_id, chain_id)  # interface params
    team_short = team_id
    placeholder_lines = (
        f"- task_id: {task_id}\n"
        f"- team_id: {team_id}\n"
        f"- team_short: {team_short}\n"
        f"- WORKSPACE_ROOT: {WORKSPACE_ROOT}\n"
        f"- report_path: {report_path}\n"
    )
    return (
        f"당신은 콘텐츠 팀 리드(아폴론)입니다. 스레드/인스타 콘텐츠 작업을 수행하세요.\n\n"
        f"## 작업 지시\n"
        f"- 작업 ID: {task_id}\n"
        f"- 작업 상세는 {task_file_path}를 읽고 파악하세요.\n\n"
        f"## 팀 구성 및 스킬\n"
        f"{WORKSPACE_ROOT}/prompts/teams/content.md를 읽고 파악하세요.\n\n"
        f"## 워크플로우\n"
        f"{WORKSPACE_ROOT}/prompts/LOGICAL-TEAM-WORKFLOW.md를 읽고 따르세요.\n"
        f"아래 값을 워크플로우에서 사용하세요:\n"
        f"{placeholder_lines}"
    )


# ── P1-1: Progressive Disclosure ──────────────────────────────────────

CRITICAL_SET = """[CRITICAL - 항상 준수]
- 금지행위: 다른 팀 디렉토리 수정 금지, 승인 없는 프로덕션 배포 금지, 보안 키/토큰 하드코딩 금지
- QC 의무: 셀프 QC 8항목 체크, qc_verify.py 자동 검증 실행, 테스트 회귀 방지
- 보고 형식: SCQA 프레임워크, 보고서 파일 저장 필수, .done 이벤트 파일 생성 필수
"""  # ~80 tokens, 변경 금지

TOKEN_LIMITS = {
    "summary": 600,
    "standard": 1800,
    "full": None,  # 무제한
}


def _count_tokens(text: str) -> int:
    """토큰 수 추정. len(text.split()) * 1.3 사용."""
    return int(len(text.split()) * 1.3)


def _truncate_to_token_limit(text: str, limit: Optional[int]) -> str:
    """텍스트를 토큰 한도 내로 자른다. CRITICAL_SET은 보존."""
    if limit is None:
        return text
    current = _count_tokens(text)
    if current <= limit:
        return text
    # 단어 단위로 자르기
    words = text.split()
    target_words = int(limit / 1.3)
    return " ".join(words[:target_words])


def build_prompt(
    team_id: str,
    task_id: str,
    task_desc: str,
    level: str = "normal",
    project_id: Optional[str] = None,
    chain_id: Optional[str] = None,
    task_type: str = "coding",
    disclosure_phase: str = "full",
) -> str:
    """팀별 dispatch 프롬프트 생성 (공통 진입점)

    목차→요약→상세 원칙 적용:
    - 프롬프트 본문(목차): task_id + 핵심 지시 + 작업 파일 경로만 전달
    - 파일(요약): task_desc를 memory/tasks/<task_id>.md에 자동 저장
    - 상세: 팀장이 코드/스펙 파일을 직접 Read하여 확인

    Args:
        team_id: 팀 ID (dev1-team ~ dev8-team)
        task_id: 작업 ID (예: task-1.1)
        task_desc: 작업 설명 (파일에 저장됨)
        level: 검증 레벨 (normal/critical/security)
        project_id: 프로젝트 ID (projects/ 하위 디렉토리명)
        chain_id: 체인 ID (Phase 자동 체이닝용, Optional)
        task_type: 작업 유형 (coding/research/check)
            - coding: QC 검증 섹션 포함 (기본값)
            - research: QC 검증 섹션 제외 (리서치, 분석 작업)
            - check: QC 검증 섹션 제외 (점검, 확인 작업)

    Returns:
        팀장에게 전달할 프롬프트 문자열
    """
    # P1-1: Progressive Disclosure 플래그 확인
    from utils.feature_flags import FeatureFlagLoader

    _ff_loader = FeatureFlagLoader()
    _pd_enabled = _ff_loader.is_enabled("progressive_disclosure_enabled")

    team = TEAM_INFO.get(team_id)
    if not team:
        raise ValueError(f"알 수 없는 팀 ID: {team_id}")

    # task_desc를 파일에 저장 (요약 파일)
    task_file_path = f"{WORKSPACE_ROOT}/memory/tasks/{task_id}.md"
    task_file = Path(task_file_path)
    task_file.parent.mkdir(parents=True, exist_ok=True)
    task_file.write_text(task_desc, encoding="utf-8")

    # timer --desc는 20자 이내 키워드만
    short_desc = task_desc[:20]

    timer_start = (
        f"python3 {WORKSPACE_ROOT}/memory/task-timer.py start {task_id} " f'--team {team_id} --desc "{short_desc}"'
    )
    timer_end = f"python3 {WORKSPACE_ROOT}/memory/task-timer.py end {task_id}"
    report_path = f"{WORKSPACE_ROOT}/memory/reports/{task_id}.md"

    if team["type"] == "direct":
        prompt = _build_direct_prompt(
            team,
            team_id,
            task_id,
            task_file_path,
            level,
            timer_start,
            timer_end,
            report_path,
            project_id=project_id,
            chain_id=chain_id,
        )
    elif team["type"] == "marketing":
        prompt = _build_marketing_prompt(
            team,
            team_id,
            task_id,
            task_file_path,
            level,
            timer_start,
            timer_end,
            report_path,
            project_id=project_id,
            chain_id=chain_id,
        )
    elif team["type"] == "consulting":
        prompt = _build_consulting_prompt(
            team,
            team_id,
            task_id,
            task_file_path,
            level,
            timer_start,
            timer_end,
            report_path,
            project_id=project_id,
            chain_id=chain_id,
        )
    elif team["type"] == "publishing":
        prompt = _build_publishing_prompt(
            team,
            team_id,
            task_id,
            task_file_path,
            level,
            timer_start,
            timer_end,
            report_path,
            project_id=project_id,
            chain_id=chain_id,
        )
    elif team["type"] == "design":
        prompt = _build_design_prompt(
            team,
            team_id,
            task_id,
            task_file_path,
            level,
            timer_start,
            timer_end,
            report_path,
            project_id=project_id,
            chain_id=chain_id,
        )
    elif team["type"] == "content":
        prompt = _build_content_prompt(
            team,
            team_id,
            task_id,
            task_file_path,
            level,
            timer_start,
            timer_end,
            report_path,
            project_id=project_id,
            chain_id=chain_id,
        )
    elif team["type"] == "mcp":
        prompt = _build_mcp_prompt(
            team,
            team_id,
            task_id,
            task_file_path,
            level,
            timer_start,
            timer_end,
            report_path,
            project_id=project_id,
            chain_id=chain_id,
        )
    else:
        prompt = _build_glm_prompt(
            team,
            team_id,
            task_id,
            task_desc,
            level,
            timer_start,
            timer_end,
            report_path,
            project_id=project_id,
            chain_id=chain_id,
        )

    # Edit 검증 리마인더 (Lv.1+, task-1881: 보고서≠구현 방지)
    prompt += (
        "\n## ★ Edit 직후 grep 검증 (필수)\n"
        "Edit 직후 반드시 grep으로 변경 반영을 확인하세요. grep 0건 = Edit 실패입니다.\n"
        "planned 항목이 1건이라도 있으면 .done 생성 금지.\n\n"
    )

    # L1 스모크테스트 리마인더 (task-1906: 실동작 확인 강제)
    prompt += (
        "\n## ★ L1 스모크테스트 (필수 — .done 생성 전)\n"
        "★ .done 전 L1 스모크테스트 필수: 실제 서버 재시작 + API curl 또는 Playwright 스크린샷 확인\n"
        "pytest PASS ≠ 실동작 확인. 상세는 DIRECT-WORKFLOW.md Step 4.8 참조.\n\n"
        "## ★ L1 스모크테스트 결과 (필수 기록)\n"
        "보고서에 아래 형식으로 L1 결과를 반드시 기록하세요:\n"
        "- 서버 재시작: [성공/실패/해당없음]\n"
        "- API 응답 확인: [curl 결과 또는 해당없음]\n"
        "- 스크린샷: [경로 또는 해당없음]\n"
        "이 섹션이 없는 보고서는 불완전 처리됩니다.\n\n"
    )

    prompt += _build_three_docs_section(task_id, level)

    # 추가 검증 (critical / security) - 코딩 작업에만 적용
    if task_type == "coding":
        prompt += _build_verification_section(level, task_id)

    # level에 따라 프롬프트 상단에 중요도 문구 삽입
    if level == "critical":
        prompt = "**[CRITICAL] 이 작업은 중요도 critical입니다. 품질 우선으로 신중하게 작업하세요.**\n\n" + prompt
    elif level == "security":
        prompt = "**[SECURITY] 이 작업은 보안 중요 작업입니다. 보안 최우선으로 작업하세요.**\n\n" + prompt

    # P1-1: Progressive Disclosure 적용
    if _pd_enabled:
        if disclosure_phase == "full":
            # full phase: CRITICAL_SET을 항상 앞에 포함
            prompt = CRITICAL_SET + "\n" + prompt
        else:
            limit = TOKEN_LIMITS.get(disclosure_phase)
            if limit is not None:
                # CRITICAL_SET은 항상 포함
                prompt = CRITICAL_SET + "\n" + _truncate_to_token_limit(prompt, limit - _count_tokens(CRITICAL_SET))

    return prompt


def _build_direct_prompt(
    team: dict,
    team_id: str,
    task_id: str,
    task_file_path: str,
    level: str,
    timer_start: str,
    timer_end: str,
    report_path: str,
    project_id: Optional[str] = None,
    chain_id: Optional[str] = None,
) -> str:
    """dev1-team, dev2-team: Opus 직접 코딩 프롬프트 (경량화)"""
    # 최소 변수만 전달 (나머지는 DIRECT-WORKFLOW.md에서 유도)
    team_short = team_id.replace("-team", "")
    placeholder_lines = (
        f"- task_id: {task_id}\n"
        f"- team_id: {team_id}\n"
        f"- team_short: {team_short}\n"
        f"- WORKSPACE_ROOT: {WORKSPACE_ROOT}\n"
        f"- CHAT_ID: {CHAT_ID}\n"
        f"- ANU_KEY: {_get_anu_key()}\n"
    )
    if project_id:
        placeholder_lines += f"- project_id: {project_id}\n"
    if chain_id:
        placeholder_lines += f"- chain_id: {chain_id}\n"

    project_map_section = _build_project_map_section(project_id)

    return (
        f"당신은 {team['leader']}, {team['role']}입니다.\n\n"
        f"## 작업 지시\n"
        f"- 작업 ID: {task_id}\n"
        f"- 팀: {team_id}\n"
        f"- 작업 상세는 {task_file_path}를 읽고 파악하세요.\n\n"
        f"{project_map_section}"
        f"## 팀원 구성\n"
        f"{team['members']}\n\n"
        f'- ⚠️ **디자인 작업 직접 수행 금지**: 이미지 생성, 배너 디자인 등은 개발팀이 직접 하지 않습니다. 디자인 관련 작업이 있으면 보고서에 "디자인팀 호출 필요"로 명시하고, satori/gemini/hybrid 스킬을 호출하지 마세요.\n\n'
        f"## 워크플로우\n"
        f"{WORKSPACE_ROOT}/prompts/DIRECT-WORKFLOW.md를 읽고 따르세요.\n"
        f"아래 값을 워크플로우에서 사용하세요:\n"
        f"{placeholder_lines}\n"
        f"## ★ Micro-commit 규칙\n"
        f"팀원이 파일 수정 완료 시 즉시 커밋:\n"
        f"```bash\n"
        f'git add -A && git commit -m "[{task_id}] {{{{팀원명}}}}: {{{{작업 요약}}}}"\n'
        f"```\n" + _build_session_monitoring_section()
    )


def _build_glm_prompt(
    team: dict,
    team_id: str,
    task_id: str,
    task_desc: str,
    level: str,
    timer_start: str,
    timer_end: str,
    report_path: str,
    project_id: Optional[str] = None,
    chain_id: Optional[str] = None,
) -> str:
    """dev8-team: 오픈클로(GLM-5)에 작업 전달, 라 팀장이 검토

    경량화: 핵심 변수 5개 + 선택 변수만 전달, 나머지는 GLM-WORKFLOW.md에서 유도.
    """
    if project_id is not None:
        isolation_rule = f"- **프로젝트 격리**: 모든 코드는 {WORKSPACE_ROOT}/projects/{project_id}/ 하위에만 작성. 다른 프로젝트 디렉토리, 시스템 코드 수정 절대 금지.\n"
    else:
        isolation_rule = f"- 이 작업은 시스템 작업입니다. 코드는 {WORKSPACE_ROOT}/teams/dev8/ 또는 작업에서 지시된 경로에 작성하세요. 다른 팀 디렉토리는 건드리지 마세요.\n"

    project_map_section = _build_project_map_section(project_id)

    # 최소 변수만 전달 (나머지는 GLM-WORKFLOW.md에서 유도)
    task_file_path = f"{WORKSPACE_ROOT}/memory/tasks/{task_id}.md"
    team_short = team_id.replace("-team", "")
    placeholder_lines = (
        f"- task_id: {task_id}\n"
        f"- team_id: {team_id}\n"
        f"- team_short: {team_short}\n"
        f"- task_file_path: {task_file_path}\n"
        f"- WORKSPACE_ROOT: {WORKSPACE_ROOT}\n"
        f"- CHAT_ID: {CHAT_ID}\n"
        f"- ANU_KEY: {_get_anu_key()}\n"
    )
    if project_id:
        placeholder_lines += f"- project_id: {project_id}\n"
    if chain_id:
        placeholder_lines += f"- chain_id: {chain_id}\n"

    return (
        f"당신은 라(Ra), 개발8팀장입니다. 아누(개발실장)에게 받은 작업을 오픈클로(GLM-5)에 전달하고, 결과를 검토합니다.\n\n"
        f"## 중요 규칙\n"
        f"- 절대 직접 코딩하지 마세요! 반드시 openclaw에 위임하세요.\n"
        f"- openclaw/GLM-5가 순차적으로 단독 작업합니다 (spawn 사용 안 함).\n"
        f"{isolation_rule}\n"
        f'- ⚠️ **디자인 작업 직접 수행 금지**: 이미지 생성, 배너 디자인, 광고 소재 제작, 카드뉴스 등 비주얼 디자인 작업은 개발팀이 직접 하지 않습니다. 디자인 관련 작업이 지시에 포함되어 있으면, 보고서에 "디자인팀 호출 필요" 로 명시하고, 직접 이미지를 생성하거나 satori/gemini/hybrid 스킬을 호출하지 마세요.\n'
        f"## 작업 지시\n"
        f"- 작업 ID: {task_id}\n"
        f"- 팀: {team_id}\n"
        f"- 작업 상세는 {WORKSPACE_ROOT}/memory/tasks/{task_id}.md를 읽고 파악하세요.\n\n"
        f"{project_map_section}"
        f"## 코딩 표준\n"
        f"코드 작성 시 {WORKSPACE_ROOT}/teams/shared/CODING-STANDARDS.md를 참조하세요.\n\n"
        f"## 결과 검토 체크리스트 (GLM 작업 완료 후 필수 확인)\n"
        f"GLM-WORKFLOW.md 섹션 7.1의 필수 체크리스트를 따르세요: `{WORKSPACE_ROOT}/teams/dev8/GLM-WORKFLOW.md`\n\n"
        f"## 워크플로우\n"
        f"{WORKSPACE_ROOT}/teams/dev8/GLM-WORKFLOW.md를 읽고 따르세요.\n"
        f"⚠️ openclaw 호출 시 반드시 `run-glm.sh` 래퍼 스크립트를 사용하세요: `bash {WORKSPACE_ROOT}/teams/dev8/run-glm.sh {task_id} {task_file_path}`\n"
        f"아래 값을 워크플로우에서 사용하세요:\n"
        f"{placeholder_lines}"
        f"\n## 세션 경량화 규칙 (필수)\n"
        f"- 도구 50회 호출 or 30분 경과 시 /compact 실행\n"
        f"- 리서치 완료 후 구현 진입 전 /compact 필수\n"
        f"- 성능 저하 징후 감지 시 즉시 /compact\n"
        f"- 중간 체크포인트: memory/checkpoints/{{task_id}}.md에 진행 상태 저장\n"
    )


def _build_mcp_prompt(
    team: dict,
    team_id: str,
    task_id: str,
    task_file_path: str,
    level: str,
    timer_start: str,
    timer_end: str,
    report_path: str,
    project_id: Optional[str] = None,
    chain_id: Optional[str] = None,
) -> str:
    """dev8-team: MCP tool(glm_backend/frontend/uxui/tester)로 팀원 위임, 라 팀장이 검토

    OpenClaw 직접 호출을 MCP tool로 대체한 새 워크플로우.
    팀장(Ra, Sonnet)이 MCP tool을 호출하여 GLM 팀원에게 작업을 위임합니다.
    """
    project_map_section = _build_project_map_section(project_id)

    team_short = team_id.replace("-team", "")
    placeholder_lines = (
        f"- task_id: {task_id}\n"
        f"- team_id: {team_id}\n"
        f"- team_short: {team_short}\n"
        f"- WORKSPACE_ROOT: {WORKSPACE_ROOT}\n"
        f"- CHAT_ID: {CHAT_ID}\n"
        f"- ANU_KEY: {_get_anu_key()}\n"
    )
    if project_id:
        placeholder_lines += f"- project_id: {project_id}\n"
    if chain_id:
        placeholder_lines += f"- chain_id: {chain_id}\n"

    return (
        f"당신은 라(Ra), 개발8팀장입니다.\n\n"
        f"## 팀원 구성\n"
        f"아누비스(백엔드), 호루스(프론트엔드), 바스테트(UX/UI), 소베크(테스터)\n\n"
        f"## 워크플로우\n"
        f"{WORKSPACE_ROOT}/prompts/DIRECT-WORKFLOW.md를 읽고 따르세요.\n"
        f"아래 값을 워크플로우에서 사용하세요:\n"
        f"{placeholder_lines}\n"
        f"## MCP Tool 기반 팀원 위임\n"
        f"팀원에게 작업을 위임할 때 MCP tool을 사용하세요:\n"
        f'- `glm_backend(task="...")` — 아누비스(백엔드, glm-5)\n'
        f'- `glm_frontend(task="...")` — 호루스(프론트엔드, glm-5)\n'
        f'- `glm_uxui(task="...")` — 바스테트(UX/UI, glm-5)\n'
        f'- `glm_tester(task="...")` — 소베크(테스터, glm-5)\n'
        f'- `glm_code(task="...", role="backend", review_cycles=1)` — 코드 작성 + 자체 리뷰\n'
        f'- `glm_generate(prompt="...", model="glm-5")` — 범용 생성\n\n'
        f"MCP tool의 결과물은 반드시 검토하고, 필요하면 직접 수정하세요.\n"
        f"GLM 결과물은 무조건 의심하고 검증합니다.\n\n"
        f"## 작업 지시\n"
        f"- 작업 ID: {task_id}\n"
        f"- 팀: {team_id}\n"
        f"- 작업 상세는 {task_file_path}를 읽고 파악하세요.\n\n"
        f"{project_map_section}"
        f'- ⚠️ **디자인 작업 직접 수행 금지**: 이미지 생성, 배너 디자인 등은 개발팀이 직접 하지 않습니다. 디자인 관련 작업이 있으면 보고서에 "디자인팀 호출 필요"로 명시하고, satori/gemini/hybrid 스킬을 호출하지 마세요.\n\n'
        f"## 코딩 표준\n"
        f"코드 작성 시 {WORKSPACE_ROOT}/teams/shared/CODING-STANDARDS.md를 참조하세요.\n"
        + _build_session_monitoring_section()
    )


def _build_three_docs_section(task_id: str, level: str) -> str:
    """3문서 활용 지침 섹션 생성 (Lv.3+ 작업: critical/security)"""
    if level not in ("critical", "security"):
        return ""
    return (
        f"\n## 3문서 활용 지침 (Lv.3+ 작업)\n"
        f"이 작업에 대한 3문서가 자동 생성되었습니다:\n"
        f"- 계획서: memory/plans/tasks/{task_id}/plan.md\n"
        f"- 맥락노트: memory/plans/tasks/{task_id}/context-notes.md\n"
        f"- 체크리스트: memory/plans/tasks/{task_id}/checklist.md\n\n"
        f"### 팀장 의무:\n"
        f"1. 작업 시작 시 plan.md의 목표/범위 확인 후 팀원에게 공유\n"
        f"2. 주요 결정 시 context-notes.md에 결정 근거 기록\n"
        f"3. 각 단계 완료 시 checklist.md의 해당 항목 [x] 체크\n"
        f"4. 작업 완료 시 3문서 최종 업데이트 (status: draft → completed)\n"
        f"\n⚠️ 보고서 작성 전 3문서 업데이트를 잊지 마세요:\n"
        f"- plan.md: status → completed (또는 in-progress)\n"
        f"- context-notes.md: 결정 근거 기록\n"
        f"- checklist.md: 완료 항목 [x] 체크\n"
        f"\n### 3 Step Why 자문 (Lv.3+)\n"
        f"설계 완료 후, 아래 3단계 자문을 수행하세요:\n"
        f"1st Why: \"왜 이 설계가 필요한가?\" → A 답변\n"
        f"2nd Why: \"왜 A가 최선의 접근인가?\" → B 답변\n"
        f"3rd Why: \"왜 B가 다른 대안보다 나은가?\" → C 답변\n"
        f"★ A-B-C 답변이 논리적으로 일관되지 않으면 설계 재검토 필수\n"
        f"결과를 context-notes.md에 기록하세요.\n"
    )


def _build_verification_section(level: str, task_id: str = "") -> str:
    """QC 규칙 파일 참조 + 게이트 지시 삽입"""
    # level 문자열 → 정수 매핑 (gate_instructions.py는 정수 레벨 사용)
    _level_to_int = {"normal": 2, "critical": 3, "security": 4}
    gate_level = _level_to_int.get(level, 2)
    gate_text = _format_gate_instructions(gate_level)

    base = (
        f"\n\n## 보고서 작성 전 셀프 QC + 자동 검증\n"
        f"{WORKSPACE_ROOT}/teams/shared/QC-RULES.md를 읽고 따르세요.\n"
        f"- 검증 레벨: {level}\n"
    )
    if level == "critical":
        base += f"- 마아트 독립 검증 필수\n"
    elif level == "security":
        base += f"- 마아트 독립 검증 + 로키 보안 감사 필수\n"

    if gate_text:
        base += f"\n## 게이트 지시 (Lv.{gate_level})\n{gate_text}\n"

    if gate_level >= 3:
        base += (
            f"\n## Codex 사전 검증 (Lv.3+ 필수)\n"
            f"python3 {WORKSPACE_ROOT}/scripts/codex_gate_check.py --task-id {task_id} --task-file {WORKSPACE_ROOT}/memory/tasks/{task_id}.md\n"
            f"결과가 FAIL이면 설계 수정 후 재실행. PASS 필요.\n"
        )
        base += (
            f"\n## ⚠️ Sanitize 게이트 (Lv.3+)\n"
            f"외부 AI(Codex/Gemini) 호출 전 반드시 sanitize 검사를 수행하세요:\n"
            f"- 대상: affected_files의 코드 + 설계 문서\n"
            f"- 마스킹 항목: 주민등록번호, 연락처, API 키, 계좌번호, 보험 증권번호\n"
            f"- 방법: `from utils.sanitize_gate import sanitize_text` 사용\n"
            f"- PII가 마스킹된 코드만 외부 AI에 전달할 것\n"
        )

    return base


def build_composite_prompt(
    composite_teams: List[str],
    task_id: str,
    task_desc: str,
    level: str = "normal",
    project_id: Optional[str] = None,
) -> str:
    """복합업무 임시팀 프롬프트 생성 (독립 진입점).

    Defense in Depth: 내부에서 composite_teams 재검증.

    Args:
        composite_teams: 논리적 팀 ID 리스트 (예: ["marketing", "design"])
        task_id: 작업 ID
        task_desc: 작업 설명
        level: 검증 레벨
        project_id: 프로젝트 ID (Optional)

    Returns:
        복합업무 임시팀장에게 전달할 프롬프트 문자열
    """
    # 내부 재검증 (Defense in Depth)
    for t in composite_teams:
        if t not in COMPOSITE_ALLOWED_TEAMS:
            raise ValueError(f"build_composite_prompt: 허용되지 않은 팀 ID: {t}")
    if len(composite_teams) < 2:
        raise ValueError("build_composite_prompt: 2개 이상의 팀 필요")

    # task_desc 파일 저장
    task_file_path = f"{WORKSPACE_ROOT}/memory/tasks/{task_id}.md"
    Path(task_file_path).parent.mkdir(parents=True, exist_ok=True)
    Path(task_file_path).write_text(task_desc, encoding="utf-8")

    # 각 팀 에이전트 로드
    team_agents = {team: _load_logical_team_agents(team) for team in composite_teams}

    # 핸드오프 필수 필드 결정
    team_set = frozenset(composite_teams)
    handoff_fields = HANDOFF_REQUIRED_FIELDS.get(team_set, DEFAULT_HANDOFF_FIELDS)

    # 프롬프트 조립
    prompt = _assemble_composite_prompt(
        composite_teams,
        team_agents,
        handoff_fields,
        task_id,
        task_file_path,
        level,
        project_id,
    )

    # level 헤더 삽입
    if level == "critical":
        prompt = "**[CRITICAL] 이 작업은 중요도 critical입니다. 품질 우선으로 신중하게 작업하세요.**\n\n" + prompt
    elif level == "security":
        prompt = "**[SECURITY] 이 작업은 보안 중요 작업입니다. 보안 최우선으로 작업하세요.**\n\n" + prompt

    return prompt


def _assemble_composite_prompt(
    composite_teams: List[str],
    team_agents: dict,
    handoff_fields: list,
    task_id: str,
    task_file_path: str,
    level: str,
    project_id: Optional[str],
) -> str:
    """복합업무 프롬프트 조립.

    9개 섹션 구조:
    1. 임시팀장 페르소나 (고정 템플릿)
    2. 작업 지시
    3. 팀별 에이전트 목록 + 스킬
    3b. 횡단조직 소환 가능 멤버
    4. Phase 관리 프로토콜
    5. 핸드오프 규격
    6. Quality Gate 규칙
    7. 보고서 규칙 (2레이어)
    8. 토큰 관리 지시
    9. 완료 마무리

    토큰 예산: 2팀 ~1,860 토큰 / 3팀 ~2,400 토큰 (4,000 상한 이내)
    """
    teams_str = ", ".join(composite_teams)
    team_short = "+".join(t.replace("-team", "") for t in composite_teams)
    report_path = f"{WORKSPACE_ROOT}/memory/reports/{task_id}.md"

    # 섹션 1: 임시팀장 페르소나
    s1 = (
        f"당신은 {teams_str} 복합업무 임시팀장입니다.\n"
        f"여러 논리적 팀의 역량을 Phase별로 조율하여 하나의 복합업무를 완수합니다.\n\n"
    )

    # 섹션 2: 작업 지시
    s2 = f"## 작업 지시\n" f"- 작업 ID: {task_id}\n" f"- 작업 상세는 {task_file_path}를 읽고 파악하세요.\n\n"

    # 섹션 3: 팀별 에이전트 목록
    s3 = "## 팀별 에이전트\n"
    for team_id in composite_teams:
        info = team_agents.get(team_id, {})
        s3 += f"\n### {team_id}\n"
        members = info.get("members_detail", info.get("members", {}))
        if isinstance(members, dict):
            for mid, minfo in members.items():
                name = minfo.get("name", mid)
                role = minfo.get("role", "")
                model = minfo.get("model", "sonnet")
                skill = minfo.get("mapped_skill", "")
                s3 += f"- **{name}** ({role}): model={model}"
                if skill:
                    s3 += f", skill={skill}"
                s3 += "\n"
        elif isinstance(members, str):
            s3 += f"- {members}\n"
    s3 += "\n"

    # 섹션 3b: 횡단조직 소환 가능 멤버
    s3b = (
        f"## 횡단조직 (소환 가능)\n\n"
        f"아래 멤버들은 팀 소속이 아니지만, QC/보안 등 특수 역할로 Task tool을 통해 소환할 수 있습니다.\n\n"
        f"- **마아트 (Ma'at)** — QC센터 팀장. 독립 품질 검증. 3자 평가 시 반드시 소환.\n"
        f"  model: claude-sonnet-4-6\n"
        f"  역할: 기획 QC, 디자인 QC, 카피 QC 등 제3자 품질 평가\n\n"
        f"- **로키 (Loki)** — 보안팀(레드팀) 팀장. Devil's Advocate. 모든 미팅/QC에 필수 참석.\n"
        f"  model: claude-opus-4-6\n"
        f"  역할: 기획/디자인의 약점 공격, 비판적 시각 제공, 디자인 퀄리티(DQ) 평가\n\n"
        f"### 소환 규칙\n"
        f'- 지시서에 "마아트 역할" / "로키 역할"이라고 되어 있으면, 자기 팀원이 역할극하지 말고 **위의 마아트/로키를 Task tool로 직접 소환**할 것\n'
        f"- 마아트/로키는 **만든 팀과 다른 3자**여야 의미가 있음 — 자기 팀원이 대체하면 3자 평가가 아님\n\n"
    )

    # 섹션 4: Phase 관리 프로토콜
    s4 = (
        f"## Phase 관리 프로토콜\n\n"
        f"### Phase 0: 계획 수립 (FYI — 감사 추적용)\n"
        f"1. task.md를 분석하여 Phase 계획을 수립하세요.\n"
        f"2. Phase 계획을 `{WORKSPACE_ROOT}/memory/tasks/{task_id}-phase-plan.md`에 저장하세요.\n"
        f"3. 각 Phase에 어떤 팀이 어떤 순서로 작업하는지 명시하세요.\n"
        f"4. Phase 계획 파일에 shell 명령, 파일 삭제, 시스템 경로 변경 지시를 포함하지 마세요.\n"
        f"5. 계획 수립 후 즉시 Phase 1을 시작하세요 (한정승인).\n\n"
        f"### Phase N (1~M): 순차 실행\n"
        f"1. 해당 Phase 팀의 에이전트만 활성화 (Task tool 사용)\n"
        f"2. 산출물을 파일로 저장\n"
        f"3. Quality Gate 검증 (아래 규칙 참조)\n"
        f"4. 핸드오프 문서 작성 (아래 규격 참조)\n\n"
        f"### Phase Final: 통합 보고서\n"
        f"모든 Phase 완료 후 통합 보고서를 {report_path}에 작성하세요.\n\n"
    )

    # 섹션 5: 핸드오프 규격
    fields_str = "\n".join(f"- [{f}]: (해당 내용 기재)" for f in handoff_fields)
    s5 = (
        f"## Phase 간 핸드오프 규격\n"
        f"각 Phase 완료 시 `{WORKSPACE_ROOT}/memory/tasks/{task_id}-handoff-{{N}}.md`를 작성하세요:\n\n"
        f"```markdown\n"
        f"## 핵심 요약 (200자 이내)\n"
        f"(다음 Phase 팀이 이 요약만 읽어도 작업 가능하도록 핵심만 기재)\n\n"
        f"## 산출물 파일\n"
        f"- (파일 경로): (설명)\n\n"
        f"## 필수 전달 사항\n"
        f"{fields_str}\n\n"
        f"## 다음 Phase 요구사항\n"
        f"- (구체적 요구사항)\n"
        f"```\n\n"
    )

    # 섹션 6: Quality Gate
    s6 = (
        f"## Quality Gate 규칙\n"
        f"- 각 Phase 산출물에 대해 품질 검증을 수행하세요.\n"
        f"- 미충족 시 재작업 지시 (최대 2회)\n"
        f"- 2회 재작업 후에도 미충족 시:\n"
        f"  1. 이슈를 보고서에 기록\n"
        f"  2. 다음 Phase로 진행\n"
        f"  3. 이 상황은 반드시 보고서의 Executive Summary에 명시\n\n"
    )

    # 섹션 7: 보고서 규칙 (2레이어)
    s7 = (
        f"## 보고서 규칙 (2레이어)\n"
        f"보고서 경로: {report_path}\n\n"
        f"### 구조:\n"
        f"1. **Executive Summary** (최상단, 300자 이내)\n"
        f"   - 전체 결과: 성공/부분성공/실패\n"
        f"   - QG 실패 건수 및 Phase\n"
        f"   - 최종 산출물 파일 경로\n"
        f"   - 후속 조치 필요 여부\n\n"
        f"2. **Phase별 상세**\n"
        f"   - 각 Phase: S(상황), C(문제), Q(질문), A(답변)\n"
        f"   - Quality Gate 통과/실패 이력\n\n"
    )

    # 섹션 8: 토큰 관리
    s8 = (
        f"## 토큰 관리\n"
        f"- Phase 전환 시 이전 Phase 산출물 전문을 컨텍스트에 올리지 마세요.\n"
        f"- 핸드오프 파일의 '핵심 요약' 섹션만 참조하세요.\n"
        f"- 상세 내용이 필요하면 파일 경로를 기록하고 필요 시에만 Read하세요.\n\n"
    )

    # 섹션 8b: 서브에이전트 결과 규칙
    s8b = (
        f"## 서브에이전트(Task tool) 결과 규칙\n"
        f"- 상세 결과는 파일로 저장하고, Task tool 반환값은 요약만 포함 (500자 이내)\n"
        f"- 요약 필수 포함: 성공/실패 여부, FAIL 항목 수/코드/사유 (있는 경우), 산출물 파일 경로\n"
        f'- "FAIL 존재 시 반드시 FAIL 코드와 사유를 요약에 포함"\n\n'
    )

    # 섹션 9: 완료 마무리
    s9 = (
        f"## 완료 마무리\n"
        f"모든 Phase 완료 및 보고서 작성 후:\n"
        f"`bash {WORKSPACE_ROOT}/scripts/finish-task.sh {task_id} {team_short} {{project_path}}`\n"
        f"- finish-task.sh가 QC → 머지 → .done → timer end → notify를 순차 수행\n"
        f"- QC FAIL 시: .failed 생성 + 수정 → finish-task.sh 재실행\n"
        f"- project_path가 없는 시스템 작업은 인자 생략 가능\n"
    )

    return s1 + s2 + s3 + s3b + s4 + s5 + s6 + s7 + s8 + s8b + s9
