#!/usr/bin/env python3
"""test_worktree_resolver.py — resolve_worktree_target_dir 단위 테스트.

쿠쿨칸(개발7팀): task-2355 worktree 인식 수정 구현의 일부.
"""

import json
import sys
import time
from pathlib import Path

# workspace utils 경로 추가
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from utils.worktree_resolver import resolve_worktree_target_dir  # type: ignore[import-untyped]


# ---------------------------------------------------------------------------
# 1. task_id가 None이거나 빈 문자열이면 (None, "none") 반환
# ---------------------------------------------------------------------------
class TestEmptyTaskId:
    def test_returns_none_for_none_task_id(self, tmp_path):
        """task_id=None → (None, "none")."""
        path, source = resolve_worktree_target_dir(
            None,
            task_timers_path=str(tmp_path / "nonexistent.json"),
            projects_root=str(tmp_path / "projects"),
        )
        assert path is None
        assert source == "none"

    def test_returns_none_for_empty_task_id(self, tmp_path):
        """task_id="" → (None, "none")."""
        path, source = resolve_worktree_target_dir(
            "",
            task_timers_path=str(tmp_path / "nonexistent.json"),
            projects_root=str(tmp_path / "projects"),
        )
        assert path is None
        assert source == "none"


# ---------------------------------------------------------------------------
# 2. task-timers.json의 worktree_path 명시 → 해당 path 반환
# ---------------------------------------------------------------------------
class TestTaskTimersResolution:
    def test_returns_path_from_task_timers(self, tmp_path):
        """task-timers.json에 worktree_path가 명시되면 반환."""
        # 가짜 worktree 디렉토리 생성 (/.worktrees/ 포함 경로)
        wt_dir = tmp_path / "projects" / "InsuRo" / ".worktrees" / "task-9999-fix"
        wt_dir.mkdir(parents=True)

        timers_data = {
            "tasks": {
                "task-9999": {
                    "worktree_path": str(wt_dir),
                }
            }
        }
        timers_file = tmp_path / "task-timers.json"
        timers_file.write_text(json.dumps(timers_data))

        path, source = resolve_worktree_target_dir(
            "task-9999",
            task_timers_path=str(timers_file),
            projects_root=str(tmp_path / "projects"),
        )
        assert path == str(wt_dir)
        assert source == "task_timers"

    def test_skips_non_worktree_explicit_path(self, tmp_path):
        """worktree_path가 /.worktrees/를 포함하지 않으면 무시하고 glob fallback."""
        # /.worktrees/ 없는 경로 지정
        non_wt_dir = tmp_path / "projects" / "InsuRo"
        non_wt_dir.mkdir(parents=True)

        timers_data = {
            "tasks": {
                "task-8888": {
                    "worktree_path": str(non_wt_dir),
                }
            }
        }
        timers_file = tmp_path / "task-timers.json"
        timers_file.write_text(json.dumps(timers_data))

        # glob에도 없으면 none 반환
        path, source = resolve_worktree_target_dir(
            "task-8888",
            task_timers_path=str(timers_file),
            projects_root=str(tmp_path / "projects"),
        )
        # /.worktrees/ 없으므로 task_timers 소스 무시 → glob도 없으므로 none
        assert path is None
        assert source == "none"

    def test_skips_nonexistent_worktree_path(self, tmp_path):
        """worktree_path가 존재하지 않는 디렉토리이면 무시."""
        timers_data = {
            "tasks": {
                "task-7777": {
                    "worktree_path": str(tmp_path / "no" / ".worktrees" / "task-7777-fix"),
                }
            }
        }
        timers_file = tmp_path / "task-timers.json"
        timers_file.write_text(json.dumps(timers_data))

        path, source = resolve_worktree_target_dir(
            "task-7777",
            task_timers_path=str(timers_file),
            projects_root=str(tmp_path / "empty_projects"),
        )
        assert path is None
        assert source == "none"


# ---------------------------------------------------------------------------
# 3. glob fallback: projects/*/.worktrees/{task_id}-* 에서 탐지
# ---------------------------------------------------------------------------
class TestGlobFallback:
    def test_glob_fallback(self, tmp_path):
        """tmp_path에 가짜 worktree 디렉토리 → glob으로 탐지."""
        wt_dir = tmp_path / "InsuRo" / ".worktrees" / "task-1234-feat"
        wt_dir.mkdir(parents=True)

        # task-timers.json 없음 (존재하지 않는 경로 사용)
        path, source = resolve_worktree_target_dir(
            "task-1234",
            task_timers_path=str(tmp_path / "no_timers.json"),
            projects_root=str(tmp_path),
        )
        assert path == str(wt_dir)
        assert source == "glob"

    def test_glob_returns_most_recent(self, tmp_path):
        """같은 task_id의 worktree 2개 → mtime 큰 쪽(최근 수정된 것) 반환."""
        wt_root = tmp_path / "InsuRo" / ".worktrees"
        wt_root.mkdir(parents=True)

        older_wt = wt_root / "task-5555-alpha"
        older_wt.mkdir()
        # mtime을 과거로 설정
        old_time = time.time() - 3600  # 1시간 전
        import os
        os.utime(str(older_wt), (old_time, old_time))

        newer_wt = wt_root / "task-5555-beta"
        newer_wt.mkdir()
        # mtime은 현재 (기본값)

        path, source = resolve_worktree_target_dir(
            "task-5555",
            task_timers_path=str(tmp_path / "no_timers.json"),
            projects_root=str(tmp_path),
        )
        assert path == str(newer_wt)
        assert source == "glob"

    def test_glob_finds_across_multiple_projects(self, tmp_path):
        """여러 프로젝트 디렉토리 중 해당 task_id worktree가 있는 것을 탐지."""
        # project_a에는 task-6666 없음
        proj_a = tmp_path / "project_a"
        proj_a.mkdir()

        # project_b에 task-6666 존재
        wt_dir = tmp_path / "project_b" / ".worktrees" / "task-6666-impl"
        wt_dir.mkdir(parents=True)

        path, source = resolve_worktree_target_dir(
            "task-6666",
            task_timers_path=str(tmp_path / "no_timers.json"),
            projects_root=str(tmp_path),
        )
        assert path == str(wt_dir)
        assert source == "glob"


# ---------------------------------------------------------------------------
# 4. worktree 어디에도 없으면 (None, "none") 반환
# ---------------------------------------------------------------------------
class TestNoWorktreeFound:
    def test_returns_none_when_no_worktree_anywhere(self, tmp_path):
        """task-timers도 없고 glob도 없으면 (None, "none")."""
        projects_dir = tmp_path / "projects"
        projects_dir.mkdir()
        # .worktrees 디렉토리가 없는 프로젝트 하나
        (projects_dir / "empty_project").mkdir()

        path, source = resolve_worktree_target_dir(
            "task-0000",
            task_timers_path=str(tmp_path / "no_timers.json"),
            projects_root=str(projects_dir),
        )
        assert path is None
        assert source == "none"

    def test_returns_none_when_projects_root_not_exist(self, tmp_path):
        """projects_root 디렉토리 자체가 없으면 (None, "none")."""
        path, source = resolve_worktree_target_dir(
            "task-1111",
            task_timers_path=str(tmp_path / "no_timers.json"),
            projects_root=str(tmp_path / "nonexistent_projects"),
        )
        assert path is None
        assert source == "none"

    def test_task_timers_load_failure_falls_through(self, tmp_path):
        """task-timers.json이 깨진 JSON이어도 예외 없이 glob fallback."""
        timers_file = tmp_path / "bad_timers.json"
        timers_file.write_text("{invalid json}")

        path, source = resolve_worktree_target_dir(
            "task-2222",
            task_timers_path=str(timers_file),
            projects_root=str(tmp_path / "empty"),
        )
        assert path is None
        assert source == "none"
