"""task-2503 회귀 테스트 파일 1 — schema YAML 형식 + 7 metadata 검증.

회장 §6 회귀 테스트 (파일 1/3):
  - schema YAML 로드 / 7 필드 정의 / parse_topology_metadata / validate_metadata
"""
import sys
from pathlib import Path

# workspace root를 sys.path에 추가
WORKSPACE = Path(__file__).resolve().parent.parent.parent
if str(WORKSPACE) not in sys.path:
    sys.path.insert(0, str(WORKSPACE))

from utils.merge_topology_gate import (  # type: ignore[import]
    SCHEMA_PATH,
    parse_topology_metadata,
    validate_metadata,
)

# ── task-2503.md spec 필수 7 키 ────────────────────────────────────────────
_SEVEN_REQUIRED_KEYS = [
    "expected_files",
    "risk_area",
    "dependency",
    "parallel_policy",
    "merge_queue_position",
    "stale_recheck_required",
    "cherry_pick_allowed",
]

# ── task-2503.md 실제 yaml 블록 (테스트용 완전 spec) ──────────────────────
TASK_2503_YAML_BLOCK = '''# task-2503 self-reference spec

```yaml
expected_files:
  - "utils/merge_topology_gate.py"
  - "memory/specs/merge-topology-gate-schema.yml"
  - "tests/regression/test_merge_topology_gate_schema_2503.py"
  - "tests/regression/test_merge_topology_gate_classifier_2503.py"
risk_area: "dispatch_layer"
dependency: "none"
parallel_policy: "serial_only"
merge_queue_position: 1
stale_recheck_required: true
cherry_pick_allowed: false
```
'''

# ── 최소 완전 spec (simple, parallel_safe) ────────────────────────────────
MINIMAL_PARALLEL_SAFE_SPEC = '''# Minimal spec

```yaml
expected_files:
  - "foo/bar.py"
risk_area: "verifier_layer"
dependency: "none"
parallel_policy: "parallel_safe"
merge_queue_position: "n/a"
stale_recheck_required: false
cherry_pick_allowed: false
```
'''


# ═══════════════════════════════════════════════════════════════════════════
# TC-1: SCHEMA_PATH 파일 존재 + yaml.safe_load 성공
# ═══════════════════════════════════════════════════════════════════════════
def test_schema_yaml_loads():
    """SCHEMA_PATH가 존재하고 yaml.safe_load 성공."""
    import yaml

    assert SCHEMA_PATH.exists(), f"SCHEMA_PATH not found: {SCHEMA_PATH}"
    with open(SCHEMA_PATH, "r", encoding="utf-8") as f:
        data = yaml.safe_load(f)
    assert data is not None
    assert isinstance(data, dict), "schema YAML must parse to a dict"


# ═══════════════════════════════════════════════════════════════════════════
# TC-2: schema fields 키에 7개 필수 metadata 모두 정의
# ═══════════════════════════════════════════════════════════════════════════
def test_schema_has_seven_required_fields():
    """schema의 fields 키에 7개 필수 metadata 모두 정의."""
    import yaml

    with open(SCHEMA_PATH, "r", encoding="utf-8") as f:
        data = yaml.safe_load(f)

    assert "fields" in data, "schema must have 'fields' key"
    defined_keys = set(data["fields"].keys())

    for key in _SEVEN_REQUIRED_KEYS:
        assert key in defined_keys, f"schema missing field: {key}"

    assert len(defined_keys) >= 7, f"schema must define at least 7 fields, got {len(defined_keys)}"


# ═══════════════════════════════════════════════════════════════════════════
# TC-3: parse_topology_metadata — task-2503 spec 파싱 시 7 키 모두 추출
# ═══════════════════════════════════════════════════════════════════════════
def test_parse_topology_metadata_extracts_seven_keys():
    """task-2503.md spec을 파싱하면 7 키 모두 dict에 추출."""
    metadata = parse_topology_metadata(TASK_2503_YAML_BLOCK)

    assert isinstance(metadata, dict), "parse_topology_metadata must return a dict"
    for key in _SEVEN_REQUIRED_KEYS:
        assert key in metadata, f"parse_topology_metadata missing key: {key}"


# ═══════════════════════════════════════════════════════════════════════════
# TC-4: validate_metadata — task-2503 spec metadata는 errors=[]
# ═══════════════════════════════════════════════════════════════════════════
def test_validate_metadata_passes_for_complete_spec():
    """task-2503.md spec의 metadata는 validate_metadata 통과 (errors=[])."""
    metadata = parse_topology_metadata(TASK_2503_YAML_BLOCK)
    errors = validate_metadata(metadata)
    assert errors == [], f"validate_metadata should return [] but got: {errors}"


# ═══════════════════════════════════════════════════════════════════════════
# TC-5: validate_metadata — 빈 dict / 일부 키 누락 시 errors 비어있지 않음
# ═══════════════════════════════════════════════════════════════════════════
def test_validate_metadata_fails_for_missing_keys():
    """빈 dict 또는 일부 키 누락 시 errors가 비어있지 않음."""
    # 빈 dict
    errors_empty = validate_metadata({})
    assert errors_empty, "empty metadata must produce errors"

    # 일부 키만 있는 경우
    partial_meta = {
        "expected_files": ["foo/bar.py"],
        "risk_area": "verifier_layer",
        # 나머지 5 키 누락
    }
    errors_partial = validate_metadata(partial_meta)
    assert errors_partial, "partial metadata must produce errors"


# ═══════════════════════════════════════════════════════════════════════════
# TC-6: validate_metadata — parallel_policy='unknown'이면 errors에 항목 존재
# ═══════════════════════════════════════════════════════════════════════════
def test_validate_metadata_fails_for_invalid_parallel_policy_value():
    """parallel_policy='unknown'이면 errors에 항목 존재."""
    metadata = {
        "expected_files": ["foo/bar.py"],
        "risk_area": "verifier_layer",
        "dependency": "none",
        "parallel_policy": "unknown_policy",  # 잘못된 값
        "merge_queue_position": "n/a",
        "stale_recheck_required": False,
        "cherry_pick_allowed": False,
    }
    errors = validate_metadata(metadata)
    assert errors, f"invalid parallel_policy must produce errors, got: {errors}"


# ═══════════════════════════════════════════════════════════════════════════
# TC-7: validate_metadata — parallel_safe인데 merge_queue_position=1이면 errors
# ═══════════════════════════════════════════════════════════════════════════
def test_validate_metadata_fails_when_parallel_safe_with_integer_queue_position():
    """parallel_safe인데 merge_queue_position=1이면 errors."""
    metadata = {
        "expected_files": ["foo/bar.py"],
        "risk_area": "verifier_layer",
        "dependency": "none",
        "parallel_policy": "parallel_safe",
        "merge_queue_position": 1,  # parallel_safe는 'n/a'여야 함
        "stale_recheck_required": False,
        "cherry_pick_allowed": False,
    }
    errors = validate_metadata(metadata)
    assert errors, (
        "parallel_safe with integer merge_queue_position must produce errors, "
        f"got: {errors}"
    )
