"""tests/regression/test_task_id_parser_v3.py — task-2547+1 회귀.

PR #95 Gemini fresh review (high 3 + medium 1) 회귀 박제:
  - 필수 fix 1: dashboard/helpers.py task-ID 제거 정규식 multi-dot 지원
  - 필수 fix 2: report_parser.py task-ID 추출 정규식 multi-dot 지원
  - 필수 fix 3: scripts/start_task_guard.py commit prefix 정규식 multi-dot 지원
  - 필수 fix 4: dispatch/__init__.py _is_design_task unused var 제거 (origin/main 기조 보존)

필수 회귀 7항목 (회장 §명시 1:1):
  - task-2523.9 실제 패턴 fixture
  - task-1234.5.6 multi-dot fixture
  - task-1234 기존 패턴 유지
  - task-1234+1 V2 retry 패턴 유지
  - task-1234.5 single-dot 패턴 유지
  - report_parser / dashboard helpers / commit prefix guard regression
  - 전체 관련 regression PASS
"""

from __future__ import annotations

import os as _os
import re
import sys as _sys

# 워크트리/메인 어느 환경이든 자신의 워크스페이스 루트를 sys.path[0]에 우선 등록.
_WROOT = _os.path.dirname(_os.path.dirname(_os.path.dirname(_os.path.abspath(__file__))))
if _WROOT in _sys.path:
    _sys.path.remove(_WROOT)
_sys.path.insert(0, _WROOT)

import pytest


# ─────────────────────────────────────────────────────────────────────────────
# (회귀 1) dashboard/helpers.py — task-ID 제거 정규식
# ─────────────────────────────────────────────────────────────────────────────

DASHBOARD_PREFIX_RE_PRIORITY1 = re.compile(
    r"^(?:task-\d+(?:\.\d+)*(?:_\d+\.\d+)?(?:_[a-z])?(?:\+\d+)?|Task\s+\d+[\.\d]*)\s*[:：]?\s*"
)
DASHBOARD_PREFIX_RE_PRIORITY2 = DASHBOARD_PREFIX_RE_PRIORITY1
DASHBOARD_PREFIX_RE_PRIORITY3 = re.compile(
    r"^(?:task-\d+(?:\.\d+)*(?:_\d+\.\d+)?(?:_[a-z])?(?:\+\d+)?|Task\s*-?\s*\d+[\.\d]*)\s*[:：]?\s*",
    flags=re.IGNORECASE,
)


@pytest.mark.parametrize(
    "raw,expected_clean",
    [
        # legacy single-dot (기존 유지)
        ("task-1234.5: 본문 제목", "본문 제목"),
        ("task-1234.5 본문 제목", "본문 제목"),
        # legacy multi-dot (회장 §명시 1:1 — task-2523.9 / task-1234.5.6)
        ("task-2523.9: 본문 제목", "본문 제목"),
        ("task-1234.5.6: 본문 제목", "본문 제목"),
        ("task-1234.5.6 본문 제목", "본문 제목"),
        # legacy base (기존 유지)
        ("task-1234: 본문 제목", "본문 제목"),
        # V2 retry (기존 유지 + 신규 인식)
        ("task-1234+1: 본문 제목", "본문 제목"),
        ("task-2487+1: 본문 제목", "본문 제목"),
        # V2 phase/parallel/retry
        ("task-2469_1.2: 본문 제목", "본문 제목"),
        ("task-2469_1.2_a+3: 본문 제목", "본문 제목"),
        # Task 키워드 변형 (priority 3 IGNORECASE)
    ],
)
def test_dashboard_priority1_prefix_strip(raw, expected_clean):
    """task-timers description 첫 줄 prefix 제거 (priority 1)."""
    cleaned = DASHBOARD_PREFIX_RE_PRIORITY1.sub("", raw).strip()
    assert cleaned == expected_clean, f"{raw!r} → {cleaned!r} (기대 {expected_clean!r})"


@pytest.mark.parametrize(
    "raw,expected_clean",
    [
        ("task-2523.9: 보고서", "보고서"),
        ("task-1234.5.6: 보고서", "보고서"),
        ("Task 1234.5.6: 보고서", "보고서"),
        ("Task-1234.5.6 보고서", "보고서"),
        ("task-1234+1 보고서", "보고서"),
    ],
)
def test_dashboard_priority3_prefix_strip_case_insensitive(raw, expected_clean):
    """보고서 H1 prefix 제거 (priority 3, IGNORECASE)."""
    cleaned = DASHBOARD_PREFIX_RE_PRIORITY3.sub("", raw).strip()
    assert cleaned == expected_clean


# ─────────────────────────────────────────────────────────────────────────────
# (회귀 2) report_parser.py — task-ID 추출 정규식
# ─────────────────────────────────────────────────────────────────────────────

REPORT_PARSER_TID_BODY = re.compile(
    r"task-\d+(?:\.\d+)*(?:_\d+\.\d+)?(?:_[a-z])?(?:\+\d+)?"
)
REPORT_PARSER_H1 = re.compile(
    r"#\s+(task-\d+(?:\.\d+)*(?:_\d+\.\d+)?(?:_[a-z])?(?:\+\d+)?)"
)


@pytest.mark.parametrize(
    "title,expected_tid",
    [
        ("# task-9.2 완료", "task-9.2"),
        ("# task-1234.5.6 보고서", "task-1234.5.6"),
        ("# task-2523.9 통합", "task-2523.9"),
        ("# task-1234 단순", "task-1234"),
        ("# task-2487+1 회복", "task-2487+1"),
        ("# task-2469_1.2_a+3 통합", "task-2469_1.2_a+3"),
    ],
)
def test_report_parser_h1_extraction_multidot(title, expected_tid):
    m = REPORT_PARSER_H1.search(title)
    assert m is not None, f"{title!r} 에서 task_id 추출 실패"
    assert m.group(1) == expected_tid


@pytest.mark.parametrize(
    "basename",
    [
        "task-9.2",
        "task-1234",
        "task-1234.5",
        "task-1234.5.6",
        "task-2523.9",
        "task-2487+1",
        "task-2469_1.2",
        "task-2469_1.2_a+3",
    ],
)
def test_report_parser_basename_match(basename):
    """파일명에서 task-ID 1:1 매치 (origin/main `re.match` 호환)."""
    assert REPORT_PARSER_TID_BODY.match(basename) is not None


# ─────────────────────────────────────────────────────────────────────────────
# (회귀 3) report_parser.py — merge_branch 추출
# ─────────────────────────────────────────────────────────────────────────────

REPORT_PARSER_MERGE_BRANCH = re.compile(
    r"(task/task-\d+(?:\.\d+)*(?:_\d+\.\d+)?(?:_[a-z])?(?:\+\d+)?-dev\d+)"
)


@pytest.mark.parametrize(
    "branch_text,expected",
    [
        ("task/task-9.1-dev2", "task/task-9.1-dev2"),
        ("task/task-1234.5.6-dev1", "task/task-1234.5.6-dev1"),
        ("task/task-2523.9-dev2", "task/task-2523.9-dev2"),
        ("task/task-2487+1-dev2", "task/task-2487+1-dev2"),
        ("task/task-2469_1.2_a-dev3", "task/task-2469_1.2_a-dev3"),
    ],
)
def test_report_parser_merge_branch_multidot(branch_text, expected):
    m = REPORT_PARSER_MERGE_BRANCH.search(branch_text)
    assert m is not None, f"{branch_text!r} 매치 실패"
    assert m.group(1) == expected


# ─────────────────────────────────────────────────────────────────────────────
# (회귀 4) scripts/start_task_guard.py — commit prefix 정규식
# ─────────────────────────────────────────────────────────────────────────────

START_TASK_GUARD_COMMIT_PREFIX = re.compile(
    r"^\[(task-\d+(?:\.\d+)*(?:_\d+\.\d+)?(?:_[a-z])?(?:\+\d+)?)\]"
)


@pytest.mark.parametrize(
    "commit_msg,expected_prefix",
    [
        ("[task-1234] 단순 prefix", "task-1234"),
        ("[task-1234.5] legacy single-dot", "task-1234.5"),
        ("[task-1234.5.6] legacy multi-dot 회귀", "task-1234.5.6"),
        ("[task-2523.9] legacy multi-dot 실제 사용례", "task-2523.9"),
        ("[task-2487+1] V2 retry", "task-2487+1"),
        ("[task-2469_1.2_a+3] V2 phase+parallel+retry", "task-2469_1.2_a+3"),
    ],
)
def test_start_task_guard_commit_prefix_multidot(commit_msg, expected_prefix):
    m = START_TASK_GUARD_COMMIT_PREFIX.match(commit_msg)
    assert m is not None, f"{commit_msg!r} prefix 매치 실패"
    assert m.group(1) == expected_prefix, (
        f"{commit_msg!r} → 캡처 {m.group(1)!r} (기대 {expected_prefix!r})"
    )


def test_start_task_guard_no_partial_truncation_multidot():
    """기존 `task-\\w+` 회귀: `task-1234.5.6` 을 `task-1234` 로 잘라 mixed 오판정하던 버그 박제."""
    m = START_TASK_GUARD_COMMIT_PREFIX.match("[task-1234.5.6] should not truncate")
    assert m is not None
    assert m.group(1) == "task-1234.5.6", "multi-dot 캡처가 잘리지 않아야 함"


# ─────────────────────────────────────────────────────────────────────────────
# (회귀 5) 통합 — 패치 적용된 SUT 실제 import 회귀
# ─────────────────────────────────────────────────────────────────────────────

def test_dashboard_helpers_module_pattern_supports_multidot():
    """dashboard/helpers.py 가 실제로 multi-dot 을 strip 하는지 SUT 단위 회귀.

    helpers 모듈은 함수 단위가 아니라 inline regex 이므로 source 텍스트에서
    task-2547+1 multi-dot 패턴 (`(?:\\.\\d+)*`) 존재를 회귀 박제로 검증한다.
    import 가능성 자체는 별도 조립 테스트가 책임지므로 여기서는 source 1:1 만 본다.
    """
    src_path = _os.path.join(_WROOT, "dashboard", "helpers.py")
    with open(src_path, encoding="utf-8") as fh:
        src = fh.read()
    assert "(?:\\.\\d+)*" in src, "dashboard/helpers.py 에 multi-dot 패턴 미존재"


def test_report_parser_module_pattern_supports_multidot():
    """report_parser.py 가 실제로 multi-dot 을 추출하는지 SUT 단위 회귀."""
    src_path = _os.path.join(_WROOT, "report_parser.py")
    with open(src_path, encoding="utf-8") as fh:
        src = fh.read()
    assert "(?:\\.\\d+)*" in src, "report_parser.py 에 multi-dot 패턴 미존재"


def test_start_task_guard_module_pattern_supports_multidot():
    """scripts/start_task_guard.py 가 multi-dot prefix 를 잘라먹지 않는지 SUT 단위 회귀."""
    src_path = _os.path.join(_WROOT, "scripts", "start_task_guard.py")
    with open(src_path, encoding="utf-8") as fh:
        src = fh.read()
    assert "(?:\\.\\d+)*" in src, "scripts/start_task_guard.py 에 multi-dot 패턴 미존재"


# ─────────────────────────────────────────────────────────────────────────────
# (회귀 6) dispatch/__init__.py — `_is_design_task` 정리 박제 (origin/main 기조 유지)
# ─────────────────────────────────────────────────────────────────────────────

def test_dispatch_init_is_design_task_no_dead_initialization():
    """`_is_design_task = False` 초기 dead 초기화가 없는지 SUT 회귀.

    PR #95 head 에서 line 4523 에 추가되었던 `_is_design_task = False` 가 모든
    경로에서 재할당되어 dead code 였음. origin/main 은 이미 정리되어 있으며
    본 task-2547+1 는 그 상태를 회귀 박제로 보존한다.
    """
    src_path = _os.path.join(_WROOT, "dispatch", "__init__.py")
    with open(src_path, encoding="utf-8") as fh:
        src = fh.read()
    # workflow None 블록 시작 직후에 `_is_design_task = False` 초기화가 없음을 검증.
    block_match = re.search(
        r"if args\.workflow is None:\s*\n(?:[ \t]*#[^\n]*\n)*([ \t]+_is_design_task\s*=\s*False[^\n]*\n)?",
        src,
    )
    assert block_match is not None, "workflow None 블록 시작 위치를 찾을 수 없음"
    # group(1): 만약 첫 dead 초기화가 존재하면 매치됨. 우리는 없기를 원함.
    assert block_match.group(1) is None, (
        "_is_design_task = False dead 초기화가 다시 들어왔습니다 (PR #95 회귀)."
    )
