"""tests/start_guard/test_mixed_commit.py
mixed commit 검사 테스트:
- test_mixed_commit_freeze: 다른 task-id 커밋 섞인 경우 → .tasks/locks/<task>.frozen 생성 + exit 1
- test_no_mixed: 같은 task-id만 있으면 exit 0
"""
from __future__ import annotations

import json
import os
import subprocess
from pathlib import Path

import pytest

SCRIPT = Path("/home/jay/workspace/.worktrees/task-2454-dev4/scripts/start_task_guard.py")


def _run(args: list[str], cwd: Path, env: dict | None = None) -> subprocess.CompletedProcess:
    """스크립트 실행 헬퍼."""
    return subprocess.run(
        ["python3", str(SCRIPT)] + args,
        cwd=str(cwd),
        capture_output=True,
        text=True,
        timeout=30,
        env={**os.environ, **(env or {})},
    )


@pytest.fixture
def git_repo_with_origin(tmp_path: Path):
    """origin/main 브랜치가 있는 임시 git 저장소 셋업."""
    # origin 역할의 bare repo 생성
    origin_path = tmp_path / "origin.git"
    origin_path.mkdir()
    subprocess.run(["git", "init", "--bare", str(origin_path)], check=True, capture_output=True)

    # 작업 repo 생성
    repo_path = tmp_path / "repo"
    repo_path.mkdir()
    subprocess.run(["git", "init", str(repo_path)], check=True, capture_output=True)

    cfg_cmds = [
        ["git", "config", "user.email", "test@test.com"],
        ["git", "config", "user.name", "Test"],
        ["git", "remote", "add", "origin", str(origin_path)],
    ]
    for cmd in cfg_cmds:
        subprocess.run(cmd, cwd=str(repo_path), check=True, capture_output=True)

    # 초기 커밋 + origin/main 설정
    (repo_path / "README.md").write_text("init", encoding="utf-8")
    subprocess.run(["git", "add", "README.md"], cwd=str(repo_path), check=True, capture_output=True)
    subprocess.run(
        ["git", "commit", "-m", "init"],
        cwd=str(repo_path), check=True, capture_output=True,
    )
    subprocess.run(
        ["git", "push", "origin", "HEAD:main"],
        cwd=str(repo_path), check=True, capture_output=True,
    )
    subprocess.run(
        ["git", "fetch", "origin"],
        cwd=str(repo_path), check=True, capture_output=True,
    )
    return repo_path


def _add_commit(repo_path: Path, filename: str, content: str, message: str) -> None:
    """파일 추가 + 커밋."""
    (repo_path / filename).write_text(content, encoding="utf-8")
    subprocess.run(["git", "add", filename], cwd=str(repo_path), check=True, capture_output=True)
    subprocess.run(
        ["git", "commit", "-m", message],
        cwd=str(repo_path), check=True, capture_output=True,
    )


# ---------------------------------------------------------------------------
# test_mixed_commit_freeze
# ---------------------------------------------------------------------------

def test_mixed_commit_freeze(git_repo_with_origin: Path):
    """다른 task-id 커밋이 섞인 경우 frozen 마커 생성 + exit 1 확인."""
    repo = git_repo_with_origin
    task_id = "task-2454"

    # 현재 task의 커밋
    _add_commit(repo, "file1.txt", "content1", f"[{task_id}] 정상 커밋")
    # 다른 task의 커밋 (이질 task-id)
    _add_commit(repo, "file2.txt", "content2", "[task-9999] 이질 커밋")

    result = _run(
        ["--task", task_id, "--check-mixed"],
        cwd=repo,
        env={"WORKSPACE_ROOT": str(repo)},
    )
    assert result.returncode != 0, (
        f"mixed commit 감지 실패 (exit 0)\nstdout: {result.stdout}\nstderr: {result.stderr}"
    )
    # freeze 마커 확인
    frozen_path = repo / ".tasks" / "locks" / f"{task_id}.frozen"
    assert frozen_path.exists(), f"freeze 마커 미생성: {frozen_path}"

    # frozen 파일 내용 검증
    frozen_data = json.loads(frozen_path.read_text(encoding="utf-8"))
    assert "alien_tasks" in frozen_data, "alien_tasks 필드 없음"
    assert "task-9999" in frozen_data["alien_tasks"], (
        f"이질 task-id 누락: {frozen_data['alien_tasks']}"
    )
    assert "mixed_tasks" in frozen_data
    assert task_id in frozen_data["mixed_tasks"]

    # stderr에 check-mixed 실패 메시지 확인
    assert "mixed" in result.stderr.lower() or "check-mixed" in result.stderr, (
        f"mixed commit 에러 메시지 없음\nstderr: {result.stderr}"
    )


# ---------------------------------------------------------------------------
# test_no_mixed
# ---------------------------------------------------------------------------

def test_no_mixed(git_repo_with_origin: Path):
    """같은 task-id 커밋만 있으면 exit 0 확인."""
    repo = git_repo_with_origin
    task_id = "task-2454"

    # 같은 task-id 커밋만 추가
    _add_commit(repo, "file1.txt", "content1", f"[{task_id}] 첫 번째 커밋")
    _add_commit(repo, "file2.txt", "content2", f"[{task_id}] 두 번째 커밋")

    result = _run(
        ["--task", task_id, "--check-mixed"],
        cwd=repo,
        env={"WORKSPACE_ROOT": str(repo)},
    )
    assert result.returncode == 0, (
        f"정상 커밋인데 exit 1 (비정상)\nstdout: {result.stdout}\nstderr: {result.stderr}"
    )
    # freeze 마커가 없어야 함
    frozen_path = repo / ".tasks" / "locks" / f"{task_id}.frozen"
    assert not frozen_path.exists(), f"freeze 마커가 잘못 생성됨: {frozen_path}"

    assert "mixed commit 없음" in result.stdout or "mixed" in result.stdout.lower(), (
        f"성공 메시지 없음\nstdout: {result.stdout}"
    )


def test_no_mixed_no_commits(git_repo_with_origin: Path):
    """origin/main..HEAD 범위에 커밋이 없는 경우 exit 0."""
    repo = git_repo_with_origin
    task_id = "task-2454"

    # 추가 커밋 없이 바로 실행
    result = _run(
        ["--task", task_id, "--check-mixed"],
        cwd=repo,
        env={"WORKSPACE_ROOT": str(repo)},
    )
    assert result.returncode == 0, (
        f"커밋 없는데 exit 1 (비정상)\nstdout: {result.stdout}\nstderr: {result.stderr}"
    )
