"""
tests/dev7/test_meta_task_validator.py

dispatch.py의 _parse_task_metadata() 검증 (task-2374 옵션 D)

카마소츠(개발7팀 테스터) 작성
"""

import importlib.util
import os
import sys
import types
from unittest.mock import patch

import pytest

# ---------------------------------------------------------------------------
# 워크트리 경로 설정: importlib로 직접 로드 (main workspace 오염 방지)
# ---------------------------------------------------------------------------

WORKTREE = "/home/jay/workspace/.worktrees/task-2374-dev7"

# dispatch — importlib 직접 로드
_dp_spec = importlib.util.spec_from_file_location(
    "dispatch_wt",
    os.path.join(WORKTREE, "dispatch.py"),
)
_dispatch_mod = importlib.util.module_from_spec(_dp_spec)  # type: ignore[arg-type]
# dispatch.py가 무거우므로 sys.modules에 등록 후 exec
sys.modules["dispatch_wt"] = _dispatch_mod
_dp_spec.loader.exec_module(_dispatch_mod)  # type: ignore[union-attr]

_parse_task_metadata = _dispatch_mod._parse_task_metadata


# ---------------------------------------------------------------------------
# Helper
# ---------------------------------------------------------------------------

def _parse(text: str) -> dict:
    return _parse_task_metadata(text)


# ---------------------------------------------------------------------------
# 테스트 케이스
# ---------------------------------------------------------------------------

class TestParseLegacyTaskNoMetadata:
    def test_empty_string_returns_default(self):
        """빈 문자열 → 기본값 code/True."""
        result = _parse("")
        assert result["kind"] == "code"
        assert result["merge_required"] is True
        assert result["source"] == "default"

    def test_plain_text_no_frontmatter_returns_default(self):
        """frontmatter도 fenced도 없으면 기본 code/True."""
        result = _parse("단순 작업 설명입니다.\n버그 수정 합니다.")
        assert result["kind"] == "code"
        assert result["merge_required"] is True
        assert result["source"] == "default"


class TestParseFrontmatterKindMeta:
    def test_kind_meta_sets_meta_and_merge_required_false(self):
        """frontmatter kind: meta → meta + merge_required=False (자동)."""
        text = "---\nkind: meta\n---\n\n작업 설명"
        result = _parse(text)
        assert result["kind"] == "meta"
        assert result["merge_required"] is False
        assert result["source"] == "frontmatter"

    def test_kind_meta_with_whitespace(self):
        """frontmatter 공백 포함 → meta 정상 파싱."""
        text = "---\nkind: meta\n\n---\n\n작업"
        result = _parse(text)
        assert result["kind"] == "meta"


class TestParseFrontmatterKindCodeExplicit:
    def test_kind_code_merge_required_true(self):
        """frontmatter kind: code, merge_required: true → code/True."""
        text = "---\nkind: code\nmerge_required: true\n---\n\n작업 설명"
        result = _parse(text)
        assert result["kind"] == "code"
        assert result["merge_required"] is True
        assert result["source"] == "frontmatter"

    def test_kind_code_merge_required_false(self):
        """frontmatter kind: code, merge_required: false → code/False."""
        text = "---\nkind: code\nmerge_required: false\n---\n\n작업"
        result = _parse(text)
        assert result["kind"] == "code"
        assert result["merge_required"] is False
        assert result["source"] == "frontmatter"


class TestParseFrontmatterMetaWithExplicitMergeRequired:
    def test_kind_meta_merge_required_true_explicit(self):
        """kind: meta + merge_required: true (명시) → meta but merge_required=True."""
        text = "---\nkind: meta\nmerge_required: true\n---\n\n작업"
        result = _parse(text)
        assert result["kind"] == "meta"
        assert result["merge_required"] is True
        assert result["source"] == "frontmatter"


class TestParseFencedYamlBlock:
    def test_fenced_yaml_kind_meta(self):
        """fenced ```yaml 안에 kind: meta → meta + merge_required=False."""
        text = "작업 설명\n\n```yaml\nkind: meta\n```\n\n추가 내용"
        result = _parse(text)
        assert result["kind"] == "meta"
        assert result["merge_required"] is False
        assert result["source"] == "fenced"

    def test_fenced_yaml_kind_code_with_merge_required(self):
        """fenced yaml kind: code + merge_required: false → code/False."""
        text = "```yaml\nkind: code\nmerge_required: false\n```"
        result = _parse(text)
        assert result["kind"] == "code"
        assert result["merge_required"] is False
        assert result["source"] == "fenced"

    def test_frontmatter_takes_priority_over_fenced(self):
        """frontmatter와 fenced 둘 다 있으면 frontmatter 우선."""
        text = "---\nkind: code\n---\n\n```yaml\nkind: meta\n```"
        result = _parse(text)
        assert result["kind"] == "code"
        assert result["source"] == "frontmatter"


class TestParseInvalidKindFallsBackDefault:
    def test_invalid_kind_falls_back_to_code(self):
        """kind: invalid_value → code (default)."""
        text = "---\nkind: invalid_value\n---\n\n작업"
        result = _parse(text)
        assert result["kind"] == "code"

    def test_unknown_kind_preserves_default_merge_required(self):
        """유효하지 않은 kind는 merge_required=True 기본값 유지."""
        text = "---\nkind: unknown\nmerge_required: false\n---"
        result = _parse(text)
        assert result["kind"] == "code"
        # merge_required는 frontmatter에서 파싱되었으면 그 값 사용
        # invalid kind는 무시되므로 source는 default 유지


class TestParseYamlUnavailableRegexFallback:
    def test_yaml_import_failure_regex_fallback(self, monkeypatch):
        """yaml import 실패 시 정규식 fallback으로 kind/merge_required 파싱."""
        import builtins
        real_import = builtins.__import__

        def mock_import(name, *args, **kwargs):
            if name == "yaml":
                raise ImportError("yaml not available")
            return real_import(name, *args, **kwargs)

        monkeypatch.setattr(builtins, "__import__", mock_import)

        text = "---\nkind: meta\nmerge_required: false\n---\n\n작업"
        result = _parse(text)
        # 정규식 fallback이 작동해야 함
        assert result["kind"] == "meta"
        assert result["source"] == "frontmatter"

    def test_yaml_import_failure_code_kind_regex(self, monkeypatch):
        """yaml 없을 때 kind: code + merge_required: true 정규식 파싱."""
        import builtins
        real_import = builtins.__import__

        def mock_import(name, *args, **kwargs):
            if name == "yaml":
                raise ImportError("yaml not available")
            return real_import(name, *args, **kwargs)

        monkeypatch.setattr(builtins, "__import__", mock_import)

        text = "---\nkind: code\nmerge_required: true\n---\n\n작업"
        result = _parse(text)
        assert result["kind"] == "code"
        assert result["merge_required"] is True


class TestParseEdgeCases:
    def test_none_input(self):
        """None 입력 시 기본값 반환."""
        # dispatch.py에서 None 체크: if not task_desc: return result
        result = _parse_task_metadata("")  # type: ignore[arg-type]
        assert result["kind"] == "code"
        assert result["merge_required"] is True

    def test_frontmatter_only_merge_required_no_kind(self):
        """frontmatter에 merge_required만 있고 kind 없음 → kind=code."""
        text = "---\nmerge_required: false\n---\n\n작업"
        result = _parse(text)
        assert result["kind"] == "code"
        assert result["merge_required"] is False
        assert result["source"] == "frontmatter"
