"""tests/dispatch/test_task_id_parsing.py — task-2471 회귀 테스트.

토르가 commit 320c5f0e 에서 신설한 ``utils.task_id_parser`` (V2 패턴) 의
+N suffix / phase / parallel 보존 동작을 영구 차단한다.

또한 commit 2cbce860 의 dispatch ``--task-file`` 자동 task_id 추출 동작도
간접 검증.

헤임달(개발2팀 테스터) 작성.
"""
from __future__ import annotations

import importlib.util
import sys
from pathlib import Path

WORKSPACE = Path(__file__).resolve().parents[2]


def _load_module(mod_name: str, file_rel: str):
    file_path = WORKSPACE / file_rel
    spec = importlib.util.spec_from_file_location(mod_name, str(file_path))
    if spec is None or spec.loader is None:
        raise ImportError(f"cannot load spec for {file_path}")
    module = importlib.util.module_from_spec(spec)
    sys.modules[mod_name] = module
    spec.loader.exec_module(module)
    return module


tip = _load_module(
    "task_id_parser_test_alias",
    "utils/task_id_parser.py",
)


# ---------------------------------------------------------------------------
# parse_task_id_v2
# ---------------------------------------------------------------------------


def test_parse_retry_suffix_preserved():
    """``task-2469+1`` -> retry 필드 ``+1`` 보존."""
    out = tip.parse_task_id_v2("task-2469+1")
    assert out == {"base": "task-2469", "phase": None, "parallel": None, "retry": "+1"}


def test_parse_phase_only():
    """``task-2469_2.1`` -> phase ``_2.1``."""
    out = tip.parse_task_id_v2("task-2469_2.1")
    assert out == {
        "base": "task-2469",
        "phase": "_2.1",
        "parallel": None,
        "retry": None,
    }


def test_parse_phase_parallel_retry_all_four():
    """``task-2469_2.1_a+3`` -> 4 필드 모두 채워짐."""
    out = tip.parse_task_id_v2("task-2469_2.1_a+3")
    assert out == {
        "base": "task-2469",
        "phase": "_2.1",
        "parallel": "_a",
        "retry": "+3",
    }


def test_parse_invalid_yields_all_none():
    """매칭 실패 시 모든 필드 None."""
    out = tip.parse_task_id_v2("invalid")
    assert out == {"base": None, "phase": None, "parallel": None, "retry": None}


def test_parse_with_only_base():
    """``task-2469`` -> phase/parallel/retry 모두 None."""
    out = tip.parse_task_id_v2("task-2469")
    assert out == {
        "base": "task-2469",
        "phase": None,
        "parallel": None,
        "retry": None,
    }


def test_parse_strips_whitespace():
    """앞뒤 공백 제거 후 매칭."""
    out = tip.parse_task_id_v2("  task-2469+5  ")
    assert out["base"] == "task-2469"
    assert out["retry"] == "+5"


# ---------------------------------------------------------------------------
# is_valid_task_id
# ---------------------------------------------------------------------------


def test_is_valid_task_id_simple():
    assert tip.is_valid_task_id("task-2469") is True


def test_is_valid_task_id_with_retry():
    assert tip.is_valid_task_id("task-2469+1") is True


def test_is_valid_task_id_full():
    assert tip.is_valid_task_id("task-2469_1.2_a+3") is True


def test_is_valid_task_id_rejects_invalid():
    assert tip.is_valid_task_id("not-a-task") is False
    assert tip.is_valid_task_id("task-abc") is False
    assert tip.is_valid_task_id("") is False


# ---------------------------------------------------------------------------
# extract_task_id_from_filename
# ---------------------------------------------------------------------------


def test_extract_from_filename_relative_path():
    """``memory/tasks/task-2469+1.md`` -> ``task-2469+1``."""
    out = tip.extract_task_id_from_filename("memory/tasks/task-2469+1.md")
    assert out == "task-2469+1"


def test_extract_from_filename_absolute_path():
    """절대 경로 + 4 필드 모두 보존."""
    out = tip.extract_task_id_from_filename("/abs/path/task-2470_1.2_b+5.md")
    assert out == "task-2470_1.2_b+5"


def test_extract_from_filename_no_extension():
    out = tip.extract_task_id_from_filename("task-1234")
    assert out == "task-1234"


def test_extract_from_filename_unrelated_returns_none():
    out = tip.extract_task_id_from_filename("README.md")
    assert out is None


def test_extract_from_filename_empty_or_invalid_input():
    assert tip.extract_task_id_from_filename("") is None
    assert tip.extract_task_id_from_filename(None) is None  # type: ignore[arg-type]


# ---------------------------------------------------------------------------
# extract_task_id_from_branch
# ---------------------------------------------------------------------------


def test_extract_from_branch_with_retry():
    """``task/task-2467+3-dev6`` -> ``task-2467+3``."""
    out = tip.extract_task_id_from_branch("task/task-2467+3-dev6")
    assert out == "task-2467+3"


def test_extract_from_branch_main_returns_none():
    """main 같은 일반 브랜치는 None."""
    out = tip.extract_task_id_from_branch("main")
    assert out is None


def test_extract_from_branch_with_phase():
    out = tip.extract_task_id_from_branch("task/task-2469_1.2-dev2")
    assert out == "task-2469_1.2"


def test_extract_from_branch_full_combo():
    """phase + parallel + retry 모두 포함된 브랜치."""
    out = tip.extract_task_id_from_branch("task/task-2470_1.2_a+5-dev3")
    assert out == "task-2470_1.2_a+5"


def test_extract_from_branch_empty_input():
    assert tip.extract_task_id_from_branch("") is None
    assert tip.extract_task_id_from_branch(None) is None  # type: ignore[arg-type]


# ---------------------------------------------------------------------------
# Pattern object 노출 검증 (회귀 방어)
# ---------------------------------------------------------------------------


def test_pattern_constant_exposed():
    """``TASK_ID_V2_PATTERN`` 가 모듈에서 노출되어야 함 (외부 사용)."""
    import re as _re

    assert hasattr(tip, "TASK_ID_V2_PATTERN")
    assert isinstance(tip.TASK_ID_V2_PATTERN, _re.Pattern)
