#!/usr/bin/env python3
"""
Task Router - 작업 설명을 분석해서 적절한 전문 팀원 선택

Usage:
    python3 memory/task-router.py route "UI 컴포넌트 만들어줘"
    python3 memory/task-router.py list
    python3 memory/task-router.py status backend-001
"""

import json
import sys
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Dict, List, Optional

# 팀 구조 파일 경로
TEAM_STRUCTURE_PATH = Path(__file__).parent / "dev-team-structure.json"


@dataclass
class Task:
    """작업 정의 데이터클래스"""

    id: str
    desc: str
    files: List[str]  # 이 작업이 건드리는 파일 목록
    depends_on: List[str]  # 선행 태스크 ID 목록
    prompt: str  # sessions_spawn 실제 프롬프트


# 키워드 매핑 (전문 분야별)
KEYWORD_MAPPING = {
    "frontend": {
        "keywords": [
            "UI",
            "ui",
            "컴포넌트",
            "화면",
            "스타일",
            "React",
            "react",
            "CSS",
            "css",
            "프론트엔드",
            "frontend",
            "페이지",
            "레이아웃",
            "디자인",
            "버튼",
            "모달",
            "폼",
            "input",
            "TypeScript",
            "javascript",
            "js",
            "jsx",
            "tsx",
        ],
        "specialist_id": "frontend-001",
    },
    "backend": {
        "keywords": [
            "API",
            "api",
            "서버",
            "DB",
            "db",
            "데이터베이스",
            "database",
            "Node.js",
            "node",
            "Python",
            "python",
            "백엔드",
            "backend",
            "엔드포인트",
            "endpoint",
            "스키마",
            "schema",
            "PostgreSQL",
            "mysql",
            "mongo",
            "redis",
            "쿼리",
            "query",
            "인증",
            "auth",
            "jwt",
            "세션",
            "session",
        ],
        "specialist_id": "backend-001",
    },
    "testing": {
        "keywords": [
            "테스트",
            "test",
            "Jest",
            "jest",
            "Pytest",
            "pytest",
            "Cypress",
            "cypress",
            "E2E",
            "e2e",
            "단위 테스트",
            "통합 테스트",
            "테스트 코드",
            "TDD",
            "tdd",
            "테스트 작성",
            "테스트 케이스",
            "mock",
            "stub",
        ],
        "specialist_id": "testing-001",
    },
    "devops": {
        "keywords": [
            "Docker",
            "docker",
            "CI/CD",
            "ci/cd",
            "cicd",
            "배포",
            "deploy",
            "AWS",
            "aws",
            "인프라",
            "infra",
            "infrastructure",
            "DevOps",
            "devops",
            "깃헙액션",
            "GitHub Actions",
            "github actions",
            "파이프라인",
            "pipeline",
            "kubernetes",
            "k8s",
            "컨테이너",
            "container",
            "빌드",
            "build",
        ],
        "specialist_id": "devops-001",
    },
}


def get_available_dev_team() -> str:
    """
    개발실 내에서 가장 한가한 팀 반환

    Returns:
        team_id: "dev1-team" | "dev2-team" | "dev3-team"
    """
    import json
    from pathlib import Path

    # 각 팀의 상태 확인
    teams = ["dev1-team", "dev2-team", "dev3-team"]
    team_status_dir = Path(__file__).parent

    available_teams = []

    for team_id in teams:
        status_file = team_status_dir / f"{team_id}-status.json"

        if status_file.exists():
            with open(status_file, "r", encoding="utf-8") as f:
                status = json.load(f)

                # available 상태인 팀 찾기
                if status.get("status") == "available" and status.get("current_task") is None:
                    available_teams.append(team_id)

    # available한 팀이 있으면 첫 번째 반환
    if available_teams:
        return available_teams[0]

    # 모두 바쁘면 dev1-team 반환 (기본)
    return "dev1-team"


def load_team_structure() -> dict:
    """팀 구조 JSON 파일 로드"""
    try:
        with open(TEAM_STRUCTURE_PATH, "r", encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        return {"error": f"팀 구조 파일을 찾을 수 없습니다: {TEAM_STRUCTURE_PATH}"}
    except json.JSONDecodeError as e:
        return {"error": f"JSON 파싱 오류: {e}"}


def get_member_info(member_id: str) -> Optional[dict]:
    """
    팀원 정보 반환 (모델 포함)

    Args:
        member_id: 팀원 ID (예: "frontend-001")

    Returns:
        팀원 정보 딕셔너리 또는 None
    """
    team = load_team_structure()
    if "error" in team:
        return None

    # 새로운 구조 (개발실)
    for sub_team in team.get("sub_teams", []):
        for member in sub_team.get("members", []):
            if member["id"] == member_id:
                return member

    # 기존 구조 (단일 팀)
    for member in team.get("members", []):
        if member["id"] == member_id:
            return member

    return None


def route_task(task_description: str) -> dict:
    """
    작업 설명을 분석해서 적절한 팀원 선택

    Args:
        task_description: 작업 설명 문자열

    Returns:
        {
            "specialist": "frontend-001",
            "model": "claude-3-sonnet",
            "model_tier": "lightweight",
            "confidence": 0.9,
            "reason": "UI 키워드 감지",
            "matched_keywords": ["UI", "컴포넌트"],
            "skills": ["React", "TypeScript", "CSS", "UI/UX"]
        }

    Examples:
        >>> route_task("UI 컴포넌트 만들어줘")
        {"specialist": "frontend-001", "model": "zai/glm-4.7-flash", ...}
        >>> route_task("API 엔드포인트 구현해줘")
        {"specialist": "backend-001", "model": "zai/glm-4.7-flash", ...}
    """
    if not task_description or not task_description.strip():
        return {
            "error": "작업 설명이 비어있습니다",
            "specialist": None,
            "model": None,
            "model_tier": None,
            "confidence": 0.0,
        }

    # 각 전문 분야별 매칭 점수 계산
    scores = {}
    matched_keywords_by_specialty = {}

    for specialty, config in KEYWORD_MAPPING.items():
        matched_keywords = []
        for keyword in config["keywords"]:
            if keyword in task_description:
                matched_keywords.append(keyword)

        if matched_keywords:
            scores[config["specialist_id"]] = len(matched_keywords)
            matched_keywords_by_specialty[config["specialist_id"]] = matched_keywords

    # 최고 점수 선택
    if not scores:
        # 키워드 매칭 실패 시 기본값 (backend)
        member_info = get_member_info("backend-001")
        return {
            "specialist": "backend-001",
            "model": member_info.get("model") if member_info else None,
            "model_tier": member_info.get("model_tier") if member_info else None,
            "confidence": 0.3,
            "reason": "키워드 매칭 실패, 기본 backend 할당",
            "matched_keywords": [],
            "warning": "명확한 키워드가 없어 기본값 할당",
            "skills": member_info.get("skills", []) if member_info else [],
        }

    best_specialist = max(scores, key=scores.get)
    matched_keywords = matched_keywords_by_specialty[best_specialist]

    # 신뢰도 계산 (매칭된 키워드 수 기반, 최대 1.0)
    confidence = min(0.5 + (len(matched_keywords) * 0.1), 1.0)

    # 사유 생성
    specialty_name = best_specialist.split("-")[0].upper()
    reason = f"{specialty_name} 키워드 감지: {', '.join(matched_keywords[:3])}"
    if len(matched_keywords) > 3:
        reason += f" 외 {len(matched_keywords) - 3}개"

    # 모델 정보 가져오기
    member_info = get_member_info(best_specialist)

    # 개발실 내 가장 한가한 팀 선택
    available_team = get_available_dev_team()

    # 팀장 ID 생성 (예: "dev1-team-lead")
    team_lead_id = available_team.replace("-team", "-team-lead")

    return {
        "specialist": best_specialist,
        "team": available_team,
        "team_lead": team_lead_id,
        "model": member_info.get("model") if member_info else None,
        "model_tier": member_info.get("model_tier") if member_info else None,
        "confidence": round(confidence, 2),
        "reason": reason,
        "matched_keywords": matched_keywords,
        "skills": member_info.get("skills", []) if member_info else [],
    }


def list_members() -> dict:
    """전체 팀원 목록 반환"""
    team = load_team_structure()
    if "error" in team:
        return team

    members = team.get("members", [])
    return {"members": [m["id"] for m in members], "count": len(members)}


def get_member_status(member_id: str) -> dict:
    """특정 팀원 상태 확인"""
    team = load_team_structure()
    if "error" in team:
        return team

    for member in team.get("members", []):
        if member["id"] == member_id:
            return {
                "id": member["id"],
                "specialty": member["specialty"],
                "status": member["status"],
                "current_task": member["current_task"],
                "skills": member["skills"],
            }

    return {
        "error": f"팀원을 찾을 수 없습니다: {member_id}",
        "available_members": [m["id"] for m in team.get("members", [])],
    }


def has_dependencies(task: Task, all_tasks: List[Task]) -> bool:
    """
    작업의 의존성 여부 확인

    확인 사항:
    1. 명시적 의존성 (depends_on)
    2. 파일 충돌 (같은 파일을 건드리는 다른 작업)

    Args:
        task: 검사할 작업
        all_tasks: 전체 작업 리스트

    Returns:
        의존성이 있으면 True, 없으면 False
    """
    # 명시적 의존성
    if task.depends_on:
        return True

    # 파일 충돌 감지
    for other in all_tasks:
        if other.id != task.id:  # 자기 자신 제외
            if set(task.files) & set(other.files):
                return True

    return False


def analyze_task_dependencies(tasks: List[Dict]) -> Dict:
    """
    작업 의존성 분석 (Task dataclass 지원)

    Args:
        tasks: 작업 리스트 (Dict 또는 Task dataclass)
            Dict 형식 (기존 호환성):
            [
                {"id": "task1", "description": "A파일 작성", "dependencies": []},
                {"id": "task2", "description": "B파일 작성", "dependencies": []},
                {"id": "task3", "description": "설계", "dependencies": []},
                {"id": "task4", "description": "구현", "dependencies": ["task3"]},
                {"id": "task5", "description": "테스트", "dependencies": ["task4"]}
            ]

            Task dataclass 형식 (새로운):
            [
                Task(id="task1", desc="A파일 작성", files=["a.py"], depends_on=[], prompt="..."),
                Task(id="task2", desc="B파일 작성", files=["b.py"], depends_on=[], prompt="..."),
                Task(id="task3", desc="설계", files=["design.md"], depends_on=[], prompt="..."),
                Task(id="task4", desc="구현", files=["impl.py"], depends_on=["task3"], prompt="..."),
                Task(id="task5", desc="테스트", files=["test.py"], depends_on=["task4"], prompt="...")
            ]

    Returns:
        {
            "parallel_tasks": ["task1", "task2"],
            "sequential_tasks": ["task3", "task4", "task5"],
            "recommendation": "hybrid",  # parallel, sequential, hybrid
            "execution_plan": {
                "parallel": [["task1", "task2"]],
                "sequential": [["task3"], ["task4"], ["task5"]]
            },
            "file_conflicts": [  # 파일 충돌 정보
                {"task1": "a.py", "task2": "a.py", "conflict": "a.py"}
            ]
        }
    """

    # Dict를 Task로 변환 (필요한 경우)
    normalized_tasks = []
    for task in tasks:
        if isinstance(task, dict):
            # 기존 형식 → 새 형식 변환
            normalized_tasks.append(
                Task(
                    id=task.get("id", ""),
                    desc=task.get("description", task.get("desc", "")),
                    files=task.get("files", []),
                    depends_on=task.get("dependencies", task.get("depends_on", [])),
                    prompt=task.get("prompt", ""),
                )
            )
        else:
            normalized_tasks.append(task)

    parallel_tasks = []
    sequential_tasks = []
    execution_plan = {"parallel": [], "sequential": []}
    file_conflicts = []

    # 1단계: 의존성 분석 (명시적 + 파일 충돌)
    for task in normalized_tasks:
        if has_dependencies(task, normalized_tasks):
            sequential_tasks.append(task.id)

            # 파일 충돌 정보 수집
            for other in normalized_tasks:
                if other.id != task.id:
                    conflict_files = set(task.files) & set(other.files)
                    if conflict_files:
                        file_conflicts.append(
                            {"task1": task.id, "task2": other.id, "conflict_files": list(conflict_files)}
                        )
        else:
            parallel_tasks.append(task.id)

    # 2단계: 실행 계획 생성
    if parallel_tasks:
        execution_plan["parallel"].append(parallel_tasks)

    # 순차 작업 그룹핑
    for task_id in sequential_tasks:
        execution_plan["sequential"].append([task_id])

    # 3단계: 추천 방식 결정
    if not sequential_tasks:
        recommendation = "parallel"
    elif not parallel_tasks:
        recommendation = "sequential"
    else:
        recommendation = "hybrid"

    return {
        "parallel_tasks": parallel_tasks,
        "sequential_tasks": sequential_tasks,
        "recommendation": recommendation,
        "execution_plan": execution_plan,
        "file_conflicts": file_conflicts,
    }


def detect_dependencies_from_description(description: str) -> List[str]:
    """
    작업 설명에서 의존성 자동 감지

    키워드 기반 감지:
    - "설계" → 의존성 없음
    - "구현" → "설계" 의존
    - "테스트" → "구현" 의존
    - "작성", "생성" → 의존성 없음
    """

    # 순차 처리 키워드
    sequential_keywords = ["구현", "테스트", "검증", "배포", "실행"]

    # 병렬 처리 키워드
    parallel_keywords = ["작성", "생성", "문서화", "로깅", "캐시"]

    # 의존성 규칙
    dependency_rules = {"구현": ["설계"], "테스트": ["구현"], "검증": ["테스트"], "배포": ["검증"]}

    for keyword in sequential_keywords:
        if keyword in description:
            return dependency_rules.get(keyword, [])

    return []


def suggest_execution_mode(task_description: str) -> Dict:
    """
    작업 설명을 기반으로 실행 모드 추천

    Returns:
        {
            "mode": "parallel" | "sequential",
            "reason": "이유",
            "confidence": 0.0-1.0
        }
    """

    # 순차 처리 키워드
    sequential_keywords = ["구현", "테스트", "검증", "배포", "실행", "설계"]

    # 병렬 처리 키워드
    parallel_keywords = ["작성", "생성", "문서화", "로깅", "캐시", "독립적"]

    # 점수 계산
    sequential_score = sum(1 for kw in sequential_keywords if kw in task_description)
    parallel_score = sum(1 for kw in parallel_keywords if kw in task_description)

    # 추천 결정
    if sequential_score > parallel_score:
        return {
            "mode": "sequential",
            "reason": f"순차 처리 키워드 {sequential_score}개 감지",
            "confidence": min(0.9, 0.5 + sequential_score * 0.1),
        }
    elif parallel_score > sequential_score:
        return {
            "mode": "parallel",
            "reason": f"병렬 처리 키워드 {parallel_score}개 감지",
            "confidence": min(0.9, 0.5 + parallel_score * 0.1),
        }
    else:
        return {"mode": "sequential", "reason": "명확하지 않음, 안전하게 순차 처리", "confidence": 0.5}  # 안전하게 순차


def main():
    """CLI 인터페이스"""
    if len(sys.argv) < 2:
        print("사용법:")
        print('  python3 memory/task-router.py route "작업 설명"')
        print("  python3 memory/task-router.py list")
        print("  python3 memory/task-router.py status <member_id>")
        sys.exit(1)

    command = sys.argv[1]

    if command == "test":
        # 실행 테스트용
        print(
            json.dumps(
                {
                    "status": "loaded",
                    "router": "TaskRouter",
                    "commands": ["route", "list", "status"],
                    "specialties": list(KEYWORD_MAPPING.keys()),
                },
                ensure_ascii=False,
            )
        )

    elif command == "route":
        if len(sys.argv) < 3:
            print("Error: 작업 설명이 필요합니다")
            print('예: python3 memory/task-router.py route "UI 컴포넌트 만들어줘"')
            sys.exit(1)

        task_description = " ".join(sys.argv[2:])
        result = route_task(task_description)
        print(json.dumps(result, ensure_ascii=False, indent=2))

    elif command == "list":
        result = list_members()
        if "error" in result:
            print(f"Error: {result['error']}")
            sys.exit(1)
        print(", ".join(result["members"]))

    elif command == "status":
        if len(sys.argv) < 3:
            print("Error: member_id가 필요합니다")
            print("예: python3 memory/task-router.py status backend-001")
            sys.exit(1)

        member_id = sys.argv[2]
        result = get_member_status(member_id)
        print(json.dumps(result, ensure_ascii=False, indent=2))

    elif command == "analyze":
        # Usage: python3 memory/task-router.py analyze <task_descriptions_json>
        if len(sys.argv) > 2:
            tasks_json = sys.argv[2]
            tasks = json.loads(tasks_json)
            result = analyze_task_dependencies(tasks)
            print(json.dumps(result, indent=2, ensure_ascii=False))
        else:
            print("Usage: python3 memory/task-router.py analyze '<json>'")

    elif command == "suggest":
        # Usage: python3 memory/task-router.py suggest "작업 설명"
        if len(sys.argv) > 2:
            description = sys.argv[2]
            result = suggest_execution_mode(description)
            print(json.dumps(result, indent=2, ensure_ascii=False))
        else:
            print("Usage: python3 memory/task-router.py suggest '<description>'")

    else:
        print(f"알 수 없는 명령어: {command}")
        print("사용 가능한 명령어: route, list, status, analyze, suggest")
        sys.exit(1)


if __name__ == "__main__":
    main()
