"""regression: task-2575 — lock_sha end-to-end 통합 테스트.

검증 항목:
1. e2e: git init repo → worktree 생성 → lock 파일에 lock_sha 기록 확인 + HEAD 일치
2. resolve_lock_sha unit: git repo → SHA40 반환
3. resolve_lock_sha 실패: non-git 디렉토리 → None

★ 모든 git 조작은 tmp_path 안에서만 수행.
★ network call 없음 (git push는 mock으로 무력화).
"""
import json
import subprocess
import sys
from pathlib import Path
from unittest.mock import patch, MagicMock

SCRIPTS = Path(__file__).resolve().parents[2] / "scripts"
sys.path.insert(0, str(SCRIPTS))

from taskctl_start import resolve_lock_sha  # type: ignore[import-not-found]  # noqa: E402


# ---------------------------------------------------------------------------
# 헬퍼: mini git repo 초기화
# ---------------------------------------------------------------------------

def _git(args: list[str], cwd: Path) -> subprocess.CompletedProcess:
    return subprocess.run(
        ["git"] + args,
        cwd=str(cwd),
        check=True,
        capture_output=True,
        text=True,
    )


def _init_repo(path: Path) -> str:
    """path에 git repo를 초기화하고 첫 커밋을 생성. HEAD SHA 반환."""
    _git(["init", "-b", "main"], path)
    _git(["config", "user.email", "test@test.com"], path)
    _git(["config", "user.name", "Test"], path)

    readme = path / "README.md"
    readme.write_text("# test\n")
    _git(["add", "README.md"], path)
    _git(["commit", "-m", "init"], path)

    result = subprocess.run(
        ["git", "rev-parse", "HEAD"],
        cwd=str(path),
        check=True,
        capture_output=True,
        text=True,
    )
    return result.stdout.strip()


# ---------------------------------------------------------------------------
# 테스트 1: e2e — cmd_create() 후 lock 파일에 lock_sha 기록 + HEAD 일치
# ---------------------------------------------------------------------------

def test_e2e_cmd_create_records_lock_sha(tmp_path):
    """git init repo에서 cmd_create() 호출 → lock 파일에 lock_sha 기록됨."""
    repo = tmp_path / "repo"
    repo.mkdir()
    _init_repo(repo)

    # worktree_manager import 시 blast_radius_parser를 찾을 수 없는 경우 mock
    fake_br_parser = MagicMock()
    fake_br_parser.parse_blast_radius.return_value = ([], [])

    with patch.dict(sys.modules, {"utils.blast_radius_parser": fake_br_parser}):
        # worktree_manager를 fresh import (이미 로드된 경우를 고려)
        if "worktree_manager" in sys.modules:
            del sys.modules["worktree_manager"]

        import worktree_manager as wm  # type: ignore[import-not-found]

        # git push는 origin 없으므로 실패해도 무방 (check=False 로 호출됨)
        # .gitignore check도 mock으로 통과
        with patch.object(wm, "_run", wraps=_patched_run_factory(wm)):
            result = wm.cmd_create(
                str(repo),
                "task-e2e",
                "dev-test",
                copy_env=False,
            )

    assert result["status"] == "created", f"예상: created, 실제: {result}"

    # lock 파일 경로 확인
    lock_path = repo / ".tasks" / "locks" / "task-e2e.lock"
    assert lock_path.exists(), "lock 파일이 생성되어야 함"

    data = json.loads(lock_path.read_text())
    assert "lock_sha" in data, "lock_sha 키가 lock 파일에 있어야 함"
    recorded_sha = data["lock_sha"]

    # HEAD SHA가 40자리 hex인지 확인
    assert len(recorded_sha) == 40
    assert all(c in "0123456789abcdef" for c in recorded_sha)

    # result에도 lock_sha가 포함되어야 함
    assert result.get("lock_sha") == recorded_sha


def _patched_run_factory(wm_module):
    """git push 명령을 무력화하는 _run 래퍼 팩토리."""
    del wm_module  # 인터페이스 호환만 유지 (실제로 wm_module은 사용하지 않음)

    def _patched(args, cwd=None, check=True, capture=True):
        # git push는 origin 없으므로 성공으로 위장
        if args and len(args) >= 2 and args[0] == "git" and args[1] == "push":
            mock_cp = MagicMock()
            mock_cp.returncode = 0
            mock_cp.stdout = ""
            mock_cp.stderr = ""
            return mock_cp
        # check-ignore 역시 0이 아닌 returncode로 .gitignore 업데이트 트리거
        # (validate_worktree_safety 데코레이터 내 check-ignore는 subprocess.run 직접 호출)
        import subprocess as _sp
        return _sp.run(
            args,
            cwd=cwd,
            check=check,
            text=True,
            stdout=_sp.PIPE if capture else None,
            stderr=_sp.PIPE if capture else None,
        )

    return _patched


# ---------------------------------------------------------------------------
# 테스트 2: resolve_lock_sha unit — git repo → SHA40 반환
# ---------------------------------------------------------------------------

def test_resolve_lock_sha_returns_sha40(tmp_path):
    """git init 후 HEAD SHA를 resolve_lock_sha가 반환하는지 검증."""
    repo = tmp_path / "resolve_test"
    repo.mkdir()
    expected_sha = _init_repo(repo)

    result = resolve_lock_sha(repo)

    assert result is not None, "SHA를 반환해야 함"
    assert len(result) == 40, f"SHA 길이가 40이어야 함: {result}"
    assert all(c in "0123456789abcdef" for c in result), f"hex 문자여야 함: {result}"
    assert result == expected_sha, "HEAD SHA와 일치해야 함"


# ---------------------------------------------------------------------------
# 테스트 3: resolve_lock_sha 실패 — non-git 디렉토리 → None
# ---------------------------------------------------------------------------

def test_resolve_lock_sha_non_git_dir_returns_none(tmp_path):
    """git repo가 아닌 디렉토리에서 resolve_lock_sha는 None을 반환해야 함."""
    non_git_dir = tmp_path / "non_git"
    non_git_dir.mkdir()

    result = resolve_lock_sha(non_git_dir)
    assert result is None, f"None이어야 하지만 {result!r} 반환됨"
