#!/usr/bin/env python3
"""
task-123.1 통합 테스트
작성자: 아르고스 (테스터, dev1-team)
대상:
  1. /home/jay/workspace/memory/pending_actions.py - PendingActions 모듈 단위 테스트
  2. /home/jay/workspace/dispatch.py - followup_action 연동 검증
  3. /home/jay/workspace/prompts/team_prompts.py - pending-actions 문구 포함 여부
  4. /home/jay/.claude/hooks/user-prompt-submit.sh - bash 구문 검증
"""

import importlib.util
import inspect
import json
import os
import subprocess
import sys

import pytest

# ---------------------------------------------------------------------------
# pending_actions 모듈 동적 import
# (memory/ 디렉토리에 __init__.py 없으므로 spec_from_file_location 사용)
# ---------------------------------------------------------------------------
_pa_spec = importlib.util.spec_from_file_location(
    "pending_actions",
    "/home/jay/workspace/memory/pending_actions.py",
)
_pa_mod = importlib.util.module_from_spec(_pa_spec)
_pa_spec.loader.exec_module(_pa_mod)
PendingActions = _pa_mod.PendingActions


# ===========================================================================
# 1. PendingActions 단위 테스트
# ===========================================================================


def test_init_creates_file(tmp_path):
    """빈 디렉토리에서 초기화 시 JSON 파일이 생성된다."""
    actions_file = str(tmp_path / "pending-actions.json")
    pa = PendingActions(actions_file=actions_file)
    assert os.path.exists(actions_file), "JSON 파일이 생성되어야 한다"
    with open(actions_file, encoding="utf-8") as f:
        data = json.load(f)
    assert "actions" in data
    assert "resolved" in data
    assert data["actions"] == []
    assert data["resolved"] == []


def test_add_action(tmp_path):
    """action 추가 후 pending 목록에 포함되어야 한다."""
    actions_file = str(tmp_path / "pending-actions.json")
    pa = PendingActions(actions_file=actions_file)
    result = pa.add_action(description="테스트 약속 1")
    pending = pa.get_pending()
    assert len(pending) == 1
    assert pending[0]["id"] == result["id"]
    assert pending[0]["description"] == "테스트 약속 1"
    assert pending[0]["status"] == "pending"


def test_add_action_id_increments(tmp_path):
    """연속 추가 시 ID가 pa-001, pa-002, ... 순서로 증가해야 한다."""
    actions_file = str(tmp_path / "pending-actions.json")
    pa = PendingActions(actions_file=actions_file)
    a1 = pa.add_action(description="약속 1")
    a2 = pa.add_action(description="약속 2")
    a3 = pa.add_action(description="약속 3")
    assert a1["id"] == "pa-001"
    assert a2["id"] == "pa-002"
    assert a3["id"] == "pa-003"


def test_resolve_action(tmp_path):
    """resolve 후 actions에서 제거, resolved에 추가, resolved_at 설정되어야 한다."""
    actions_file = str(tmp_path / "pending-actions.json")
    pa = PendingActions(actions_file=actions_file)
    added = pa.add_action(description="이행할 약속")
    action_id = added["id"]

    resolved = pa.resolve_action(action_id)

    assert resolved is not None, "resolve 결과가 None이 아니어야 한다"
    assert resolved["id"] == action_id
    assert resolved["status"] == "resolved"
    assert resolved["resolved_at"] is not None, "resolved_at이 설정되어야 한다"

    # actions에서 제거되었는지 확인
    pending = pa.get_pending()
    assert all(a["id"] != action_id for a in pending), "actions에서 제거되어야 한다"

    # resolved에 추가되었는지 확인
    all_data = pa.list_all(include_resolved=True)
    assert any(a["id"] == action_id for a in all_data["resolved"]), "resolved 목록에 있어야 한다"


def test_resolve_nonexistent(tmp_path):
    """존재하지 않는 ID resolve 시 None을 반환해야 한다."""
    actions_file = str(tmp_path / "pending-actions.json")
    pa = PendingActions(actions_file=actions_file)
    result = pa.resolve_action("pa-999")
    assert result is None


def test_count_pending(tmp_path):
    """추가/해결 후 카운트가 정확해야 한다."""
    actions_file = str(tmp_path / "pending-actions.json")
    pa = PendingActions(actions_file=actions_file)

    assert pa.count_pending() == 0

    a1 = pa.add_action(description="약속 A")
    a2 = pa.add_action(description="약속 B")
    a3 = pa.add_action(description="약속 C")
    assert pa.count_pending() == 3

    pa.resolve_action(a1["id"])
    assert pa.count_pending() == 2

    pa.resolve_action(a2["id"])
    pa.resolve_action(a3["id"])
    assert pa.count_pending() == 0


def test_list_all_with_resolved(tmp_path):
    """include_resolved=True 시 resolved 항목이 포함되어야 한다."""
    actions_file = str(tmp_path / "pending-actions.json")
    pa = PendingActions(actions_file=actions_file)
    a1 = pa.add_action(description="pending 약속")
    a2 = pa.add_action(description="resolve할 약속")
    pa.resolve_action(a2["id"])

    result = pa.list_all(include_resolved=True)
    assert "actions" in result
    assert "resolved" in result
    assert len(result["actions"]) == 1
    assert result["actions"][0]["id"] == a1["id"]
    assert len(result["resolved"]) == 1
    assert result["resolved"][0]["id"] == a2["id"]


def test_list_all_without_resolved(tmp_path):
    """include_resolved=False(기본) 시 resolved 항목이 포함되지 않아야 한다."""
    actions_file = str(tmp_path / "pending-actions.json")
    pa = PendingActions(actions_file=actions_file)
    a1 = pa.add_action(description="pending 약속")
    a2 = pa.add_action(description="resolve할 약속")
    pa.resolve_action(a2["id"])

    result = pa.list_all(include_resolved=False)
    assert "actions" in result
    assert "resolved" not in result, "include_resolved=False 시 resolved 키가 없어야 한다"
    assert len(result["actions"]) == 1
    assert result["actions"][0]["id"] == a1["id"]


def test_backup_recovery(tmp_path):
    """JSON 파일이 깨진 경우 .bak 파일에서 복구되어야 한다."""
    actions_file = str(tmp_path / "pending-actions.json")
    backup_file = actions_file + ".bak"

    pa = PendingActions(actions_file=actions_file)
    pa.add_action(description="백업에서 복구할 약속")

    # 현재 정상 파일을 백업으로 복사
    import shutil
    shutil.copy2(actions_file, backup_file)

    # 원본 JSON 파일을 손상
    with open(actions_file, "w", encoding="utf-8") as f:
        f.write("{ invalid json !!!")

    # 손상된 상태에서 새 인스턴스 생성 — 백업에서 복구되어야 함
    pa2 = PendingActions(actions_file=actions_file)
    pending = pa2.get_pending()
    assert len(pending) == 1, "백업에서 복구된 pending 항목이 1개이어야 한다"
    assert pending[0]["description"] == "백업에서 복구할 약속"


def test_empty_description_accepted(tmp_path):
    """빈 description도 추가 가능해야 한다."""
    actions_file = str(tmp_path / "pending-actions.json")
    pa = PendingActions(actions_file=actions_file)
    result = pa.add_action(description="")
    assert result["id"] == "pa-001"
    assert result["description"] == ""
    assert pa.count_pending() == 1


# ===========================================================================
# 2. dispatch.py followup 연동 테스트
# ===========================================================================


def test_dispatch_imports_pending_actions():
    """dispatch.py가 PendingActions를 정상적으로 import하는지 확인한다."""
    sys.path.insert(0, "/home/jay/workspace")
    # 이미 캐시되어 있을 수 있으므로 pop 후 재 import
    if "dispatch" in sys.modules:
        dispatch_mod = sys.modules["dispatch"]
    else:
        dispatch_mod = importlib.import_module("dispatch")

    assert hasattr(dispatch_mod, "PendingActions"), "dispatch 모듈에 PendingActions 속성이 있어야 한다"
    assert dispatch_mod.PendingActions is not None


def test_dispatch_function_accepts_followup_action():
    """dispatch() 함수가 followup_action 파라미터를 받는지 확인한다."""
    sys.path.insert(0, "/home/jay/workspace")
    if "dispatch" in sys.modules:
        dispatch_mod = sys.modules["dispatch"]
    else:
        dispatch_mod = importlib.import_module("dispatch")

    sig = inspect.signature(dispatch_mod.dispatch)
    assert "followup_action" in sig.parameters, "dispatch()에 followup_action 파라미터가 있어야 한다"


def test_dispatch_cli_has_followup_option():
    """dispatch.py CLI에 --followup 옵션이 있는지 확인한다."""
    result = subprocess.run(
        ["python3", "/home/jay/workspace/dispatch.py", "--help"],
        capture_output=True,
        text=True,
    )
    assert "--followup" in result.stdout, "--followup 옵션이 help 출력에 있어야 한다"


# ===========================================================================
# 3. team_prompts.py 프롬프트 검증
# ===========================================================================


def test_direct_prompt_includes_pending_actions():
    """dev1-team 프롬프트에 pending_actions 확인 지시가 포함되는지 확인한다."""
    sys.path.insert(0, "/home/jay/workspace")
    # 캐시 무효화 후 재 import
    for mod_name in list(sys.modules.keys()):
        if "team_prompts" in mod_name:
            del sys.modules[mod_name]

    from prompts.team_prompts import build_prompt

    task_id = "task-test-1"
    prompt = build_prompt("dev1-team", task_id, "테스트 작업", "normal")

    assert "pending_actions.py pending" in prompt, \
        "dev1-team 프롬프트에 'pending_actions.py pending' 문구가 있어야 한다"
    assert "미이행 약속" in prompt, \
        "dev1-team 프롬프트에 '미이행 약속' 문구가 있어야 한다"

    # cleanup
    task_file = "/home/jay/workspace/memory/tasks/task-test-1.md"
    if os.path.exists(task_file):
        os.remove(task_file)


def test_glm_prompt_includes_pending_actions():
    """dev3-team 프롬프트에 pending_actions 확인 지시가 포함되는지 확인한다."""
    sys.path.insert(0, "/home/jay/workspace")
    for mod_name in list(sys.modules.keys()):
        if "team_prompts" in mod_name:
            del sys.modules[mod_name]

    from prompts.team_prompts import build_prompt

    task_id = "task-test-2"
    prompt = build_prompt("dev3-team", task_id, "테스트 작업", "normal")

    assert "pending_actions.py pending" in prompt, \
        "dev3-team 프롬프트에 'pending_actions.py pending' 문구가 있어야 한다"
    assert "미이행 약속" in prompt, \
        "dev3-team 프롬프트에 '미이행 약속' 문구가 있어야 한다"

    # cleanup
    task_file = "/home/jay/workspace/memory/tasks/task-test-2.md"
    if os.path.exists(task_file):
        os.remove(task_file)


# ===========================================================================
# 4. Hook 구문 검증
# ===========================================================================

HOOK_PATH = "/home/jay/.claude/hooks/user-prompt-submit.sh"


def test_hook_syntax_valid():
    """user-prompt-submit.sh의 bash 구문이 유효한지 확인한다."""
    result = subprocess.run(
        ["bash", "-n", HOOK_PATH],
        capture_output=True,
        text=True,
    )
    assert result.returncode == 0, \
        f"bash 구문 오류:\n{result.stderr}"


def test_hook_contains_pending_actions_check():
    """user-prompt-submit.sh에 pending-actions 체크 코드가 있는지 확인한다."""
    with open(HOOK_PATH, encoding="utf-8") as f:
        content = f.read()

    assert "pending_actions.py count" in content, \
        "hook에 'pending_actions.py count' 코드가 있어야 한다"
    assert "pending_actions.py pending" in content, \
        "hook에 'pending_actions.py pending' 코드가 있어야 한다"
    assert "미이행 약속" in content, \
        "hook에 '미이행 약속' 문자열이 있어야 한다"
