"""tests/handoff/test_schema.py
handoff-schema.json 스키마 검증 테스트:
- test_schema_self_validity: Draft202012Validator.check_schema() PASS
- test_schema_required_fields: 필수 필드 누락 시 validation 실패
- test_schema_oneof_pending: pending_work + pending_work_path 동시 존재 시 fail
- test_schema_pattern_task_id: 잘못된 task-id 패턴 → fail
"""
from __future__ import annotations

import json
from pathlib import Path

import jsonschema
import pytest
from jsonschema import Draft202012Validator

SCHEMA_PATH = Path("/home/jay/workspace/.worktrees/task-2454-dev4/memory/specs/handoff-schema.json")

# 테스트에서 사용할 유효한 기본 handoff 데이터
VALID_BASE = {
    "task_id": "task-2454",
    "schema_version": "1.0",
    "previous_bot": "dev4",
    "current_branch": "task/task-2454-dev4",
    "base_sha": "abc1234",
    "head_sha": "def5678",
    "changed_paths": ["scripts/start_task_guard.py"],
    "allowed_paths": [],
    "forbidden_paths": [],
    "test_results": {},
    "handoff_reason": "interrupt",
    "created_at": "2026-05-05T12:00:00Z",
}


@pytest.fixture(scope="module")
def schema() -> dict:
    """handoff-schema.json 로드."""
    assert SCHEMA_PATH.exists(), f"스키마 파일 없음: {SCHEMA_PATH}"
    return json.loads(SCHEMA_PATH.read_text(encoding="utf-8"))


@pytest.fixture(scope="module")
def validator(schema: dict) -> "Draft202012Validator":
    """Draft202012Validator 인스턴스."""
    return Draft202012Validator(schema)


# ---------------------------------------------------------------------------
# test_schema_self_validity
# ---------------------------------------------------------------------------

def test_schema_self_validity(schema: dict):
    """스키마 자체가 유효한 JSON Schema Draft 2020-12인지 확인."""
    try:
        Draft202012Validator.check_schema(schema)
    except jsonschema.SchemaError as e:
        pytest.fail(f"스키마 자체 검증 실패: {e}")


# ---------------------------------------------------------------------------
# test_schema_valid_base
# ---------------------------------------------------------------------------

def test_schema_valid_base(validator: "Draft202012Validator"):
    """유효한 기본 데이터가 스키마 검증을 통과하는지 확인."""
    errors = list(validator.iter_errors(VALID_BASE))
    assert not errors, f"유효한 데이터 검증 실패: {[e.message for e in errors]}"


# ---------------------------------------------------------------------------
# test_schema_required_fields
# ---------------------------------------------------------------------------

@pytest.mark.parametrize("missing_field", [
    "task_id",
    "schema_version",
    "previous_bot",
    "current_branch",
    "base_sha",
    "head_sha",
    "changed_paths",
    "allowed_paths",
    "forbidden_paths",
    "test_results",
    "handoff_reason",
    "created_at",
])
def test_schema_required_fields(validator: "Draft202012Validator", missing_field: str):
    """필수 필드 누락 시 스키마 검증 실패 확인."""
    data = dict(VALID_BASE)
    del data[missing_field]
    errors = list(validator.iter_errors(data))
    assert errors, f"필수 필드 '{missing_field}' 누락인데 검증 통과 (비정상)"


# ---------------------------------------------------------------------------
# test_schema_oneof_pending
# ---------------------------------------------------------------------------

def test_schema_oneof_pending_both_present(validator: "Draft202012Validator"):
    """pending_work + pending_work_path 동시 존재 시 검증 실패."""
    data = dict(VALID_BASE)
    data["pending_work"] = "잔여 작업 내용"
    data["pending_work_path"] = "memory/handoffs/task-2454-pending.txt"
    errors = list(validator.iter_errors(data))
    assert errors, (
        "pending_work + pending_work_path 동시 존재인데 검증 통과 (oneOf 위반)"
    )


def test_schema_oneof_pending_inline_only(validator: "Draft202012Validator"):
    """pending_work만 있을 때 검증 통과."""
    data = dict(VALID_BASE)
    data["pending_work"] = "잔여 작업 내용 (4000자 이하)"
    errors = list(validator.iter_errors(data))
    assert not errors, f"pending_work 인라인만 있는데 검증 실패: {[e.message for e in errors]}"


def test_schema_oneof_pending_path_only(validator: "Draft202012Validator"):
    """pending_work_path만 있을 때 검증 통과."""
    data = dict(VALID_BASE)
    data["pending_work_path"] = "memory/handoffs/task-2454-pending.txt"
    errors = list(validator.iter_errors(data))
    assert not errors, f"pending_work_path만 있는데 검증 실패: {[e.message for e in errors]}"


# ---------------------------------------------------------------------------
# test_schema_pattern_task_id
# ---------------------------------------------------------------------------

@pytest.mark.parametrize("invalid_task_id", [
    "task2454",          # 하이픈 없음
    "TASK-2454",         # 대문자
    "task-abc",          # 숫자 아님
    "task-2454-dev4",    # bot 접미사 포함
    "  task-2454  ",     # 공백 포함
    "task-",             # 번호 없음
    "",                  # 빈 문자열
])
def test_schema_pattern_task_id_invalid(validator: "Draft202012Validator", invalid_task_id: str):
    """잘못된 task-id 패턴 → 검증 실패."""
    data = dict(VALID_BASE)
    data["task_id"] = invalid_task_id
    errors = list(validator.iter_errors(data))
    assert errors, (
        f"잘못된 task-id '{invalid_task_id}'인데 검증 통과 (패턴 검증 없음?)"
    )


@pytest.mark.parametrize("valid_task_id", [
    "task-2454",
    "task-1",
    "task-99999",
    "task-2454.1",
    "task-100.2",
])
def test_schema_pattern_task_id_valid(validator: "Draft202012Validator", valid_task_id: str):
    """유효한 task-id 패턴 → 검증 통과."""
    data = dict(VALID_BASE)
    data["task_id"] = valid_task_id
    # current_branch도 패턴에 맞게 조정
    data["current_branch"] = f"task/{valid_task_id}-dev4"
    errors = list(validator.iter_errors(data))
    assert not errors, (
        f"유효한 task-id '{valid_task_id}'인데 검증 실패: {[e.message for e in errors]}"
    )


# ---------------------------------------------------------------------------
# test_schema_handoff_reason_enum
# ---------------------------------------------------------------------------

@pytest.mark.parametrize("invalid_reason", [
    "pause",
    "stop",
    "INTERRUPT",
    "done",
    "",
])
def test_schema_invalid_handoff_reason(validator: "Draft202012Validator", invalid_reason: str):
    """잘못된 handoff_reason → 검증 실패."""
    data = dict(VALID_BASE)
    data["handoff_reason"] = invalid_reason
    errors = list(validator.iter_errors(data))
    assert errors, f"잘못된 reason '{invalid_reason}'인데 검증 통과"


# ---------------------------------------------------------------------------
# test_schema_additional_properties
# ---------------------------------------------------------------------------

def test_schema_no_additional_properties(validator: "Draft202012Validator"):
    """additionalProperties: false → 정의되지 않은 필드 추가 시 검증 실패."""
    data = dict(VALID_BASE)
    data["unexpected_field"] = "value"
    errors = list(validator.iter_errors(data))
    assert errors, "정의되지 않은 필드가 있는데 검증 통과 (additionalProperties 위반)"


# ---------------------------------------------------------------------------
# test_schema_pending_work_maxlength
# ---------------------------------------------------------------------------

def test_schema_pending_work_maxlength(validator: "Draft202012Validator"):
    """pending_work가 4000자 초과 시 검증 실패."""
    data = dict(VALID_BASE)
    data["pending_work"] = "x" * 4001
    errors = list(validator.iter_errors(data))
    assert errors, "4000자 초과 pending_work인데 검증 통과 (maxLength 위반)"
