"""tests/regression/test_dispatch_hardening_2487.py — task-2487 회귀 (Group A, task-2547 corrected).

dispatch 영역의 V2 task ID 패턴 검증 회귀 — utils.task_id_parser SSOT 위임을
dispatch/__init__.py 가 사용하는지 검증한다.

dispatch.__init__ 모듈은 대형이라 직접 import 하지 않고:
  1. utils.task_id_parser.is_valid_task_id / parse_task_id_v2 V2 인식
  2. dispatch/__init__.py 소스 메타 검증 (is_valid_task_id_with_legacy 호출 존재)
"""
from __future__ import annotations

import importlib.util
import sys
from pathlib import Path

import pytest

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

# task-2551 §명시: main은 corrected scope 4 files (PR #97)만 반영. dispatch SSOT 위임 확장은
# 미반영. 본 어설션은 후속 PR로 SSOT 위임 확장이 main에 반영될 때 활성화.
_SSOT_PENDING_REASON = (
    "main에 dispatch SSOT 위임 미적용 (PR #97 corrected scope 4 files만 머지). "
    "task-2487 chain 후속 PR에서 SSOT 확장 후 활성화 (회장 §명시 task-2551)."
)


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("tip_2487_dispatch", "utils/task_id_parser.py")


def test_dispatch_valid_base():
    assert tip.is_valid_task_id("task-1234") is True


def test_dispatch_valid_retry():
    assert tip.is_valid_task_id("task-1234+1") is True


def test_dispatch_valid_phase():
    assert tip.is_valid_task_id("task-1234_1.2") is True


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


def test_dispatch_invalid_no_prefix():
    assert tip.is_valid_task_id("1234") is False


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


def test_dispatch_invalid_alpha_num():
    assert tip.is_valid_task_id("task-abc") is False


def test_dispatch_invalid_empty():
    assert tip.is_valid_task_id("") is False


@pytest.mark.skip(reason=_SSOT_PENDING_REASON)
def test_dispatch_source_uses_is_valid_task_id_with_legacy():
    """dispatch/__init__.py 소스에 is_valid_task_id_with_legacy 호출이 있어야 한다."""
    src = (WORKSPACE / "dispatch" / "__init__.py").read_text(encoding="utf-8")
    assert "is_valid_task_id_with_legacy" in src, (
        "dispatch/__init__.py에 is_valid_task_id_with_legacy 호출 없음 — V2+legacy 검증 미적용"
    )


def test_dispatch_source_imports_task_id_parser():
    src = (WORKSPACE / "dispatch" / "__init__.py").read_text(encoding="utf-8")
    assert "utils.task_id_parser" in src or "from utils.task_id_parser" in src, (
        "dispatch/__init__.py에 utils.task_id_parser import 없음"
    )


@pytest.mark.skip(reason=_SSOT_PENDING_REASON)
def test_dispatch_source_no_inline_v2_pattern_recompile():
    """task-2547: dispatch/__init__.py 내부 TASK_ID_V2_PATTERN 인라인 재정의 제거 어설션."""
    src = (WORKSPACE / "dispatch" / "__init__.py").read_text(encoding="utf-8")
    assert 'TASK_ID_V2_PATTERN = re.compile(r"^task-' not in src, (
        "dispatch/__init__.py에 TASK_ID_V2_PATTERN 인라인 재정의가 남아있음 — SSOT 위반"
    )


def test_dispatch_parse_base_only():
    out = tip.parse_task_id_v2("task-1234")
    assert out["base"] == "task-1234"
    assert out["phase"] is None
    assert out["parallel"] is None
    assert out["retry"] is None


def test_dispatch_parse_retry_suffix():
    out = tip.parse_task_id_v2("task-1234+1")
    assert out["base"] == "task-1234"
    assert out["retry"] == "+1"
    assert out["phase"] is None
    assert out["parallel"] is None


def test_dispatch_parse_phase_suffix():
    out = tip.parse_task_id_v2("task-1234_1.2")
    assert out["base"] == "task-1234"
    assert out["phase"] == "_1.2"
    assert out["parallel"] is None
    assert out["retry"] is None


def test_dispatch_parse_full_combo():
    out = tip.parse_task_id_v2("task-1234_1.2_a+3")
    assert out["base"] == "task-1234"
    assert out["phase"] == "_1.2"
    assert out["parallel"] == "_a"
    assert out["retry"] == "+3"
