"""
Test stubs for AS-series agentskills.io rule validation (AS001 through AS006).

Wave 0 TDD scaffold — all tests fail RED (ImportError) until plan 02-02
creates the skilllint.rules.as_series module.

Test IDs map to VALIDATION.md task ID 2-05-01 for traceability.
"""

from __future__ import annotations

import pathlib
import textwrap

# This import fails RED until plan 02-02 creates the module.
from skilllint.rules.as_series import check_skill_md

FIXTURES = pathlib.Path(__file__).parent / "fixtures"


def _violations_with_code(violations: list[dict], code: str) -> list[dict]:
    """Filter violations list by rule code."""
    return [v for v in violations if v.get("code") == code]


# ---------------------------------------------------------------------------
# AS001: name format — lowercase alphanumeric + hyphens only
# ---------------------------------------------------------------------------


def test_as001_name_format_valid(tmp_path: pathlib.Path):
    """name 'my-skill' passes AS001 (no violation produced)."""
    skill_dir = tmp_path / "my-skill"
    skill_dir.mkdir()
    skill_md = skill_dir / "SKILL.md"
    skill_md.write_text(
        textwrap.dedent("""\
            ---
            name: my-skill
            description: A valid skill description.
            ---

            Body content.
        """)
    )
    violations = check_skill_md(skill_md)
    assert _violations_with_code(violations, "AS001") == [], (
        f"Expected no AS001 violations for valid name, got: {violations}"
    )


def test_as001_name_format_invalid(tmp_path: pathlib.Path):
    """name 'My_Skill!' produces AS001 error."""
    skill_dir = tmp_path / "my-skill"
    skill_dir.mkdir()
    skill_md = skill_dir / "SKILL.md"
    skill_md.write_text(
        textwrap.dedent("""\
            ---
            name: My_Skill!
            description: A skill with an invalid name.
            ---

            Body content.
        """)
    )
    violations = check_skill_md(skill_md)
    assert _violations_with_code(violations, "AS001") != [], "Expected AS001 violation for name 'My_Skill!'"


# ---------------------------------------------------------------------------
# AS002: name matches parent directory name
# ---------------------------------------------------------------------------


def test_as002_name_matches_directory(tmp_path: pathlib.Path):
    """name 'foo' in directory 'bar/' produces AS002 error."""
    skill_dir = tmp_path / "bar"
    skill_dir.mkdir()
    skill_md = skill_dir / "SKILL.md"
    skill_md.write_text(
        textwrap.dedent("""\
            ---
            name: foo
            description: Name does not match directory name bar.
            ---

            Body content.
        """)
    )
    violations = check_skill_md(skill_md)
    assert _violations_with_code(violations, "AS002") != [], (
        "Expected AS002 violation when name 'foo' does not match directory 'bar'"
    )


# ---------------------------------------------------------------------------
# AS003: description must be present and non-empty
# ---------------------------------------------------------------------------


def test_as003_description_present(tmp_path: pathlib.Path):
    """Missing description field produces AS003 error."""
    skill_dir = tmp_path / "my-skill"
    skill_dir.mkdir()
    skill_md = skill_dir / "SKILL.md"
    skill_md.write_text(
        textwrap.dedent("""\
            ---
            name: my-skill
            ---

            Body content.
        """)
    )
    violations = check_skill_md(skill_md)
    assert _violations_with_code(violations, "AS003") != [], "Expected AS003 violation when description is missing"


# ---------------------------------------------------------------------------
# AS004: description must not contain HTML tags
# ---------------------------------------------------------------------------


def test_as004_description_unquoted_colon(tmp_path: pathlib.Path):
    """description containing unquoted colon produces AS004 error."""
    skill_dir = tmp_path / "my-skill"
    skill_dir.mkdir()
    skill_md = skill_dir / "SKILL.md"
    skill_md.write_text(
        textwrap.dedent("""\
            ---
            name: my-skill
            description: Use this: for examples Context: testing
            ---

            Body content.
        """)
    )
    violations = check_skill_md(skill_md)
    assert _violations_with_code(violations, "AS004") != [], (
        "Expected AS004 violation when description contains unquoted colons"
    )
    # Check that fix is provided
    as004 = _violations_with_code(violations, "AS004")[0]
    assert "fix" in as004, "AS004 should provide a fix suggestion"
    assert "Wrap description in quotes" in as004["fix"]


def test_as004_angle_brackets_allowed(tmp_path: pathlib.Path):
    """description with angle brackets but no colons should NOT trigger AS004."""
    skill_dir = tmp_path / "my-skill"
    skill_dir.mkdir()
    skill_md = skill_dir / "SKILL.md"
    skill_md.write_text(
        textwrap.dedent("""\
            ---
            name: my-skill
            description: Use this for <testing> purposes only
            ---

            Body content.
        """)
    )
    violations = check_skill_md(skill_md)
    assert _violations_with_code(violations, "AS004") == [], "AS004 should NOT fire for angle brackets without colons"


# ---------------------------------------------------------------------------
# AS005: SKILL.md body token count warning (> TOKEN_WARNING_THRESHOLD tokens)
# ---------------------------------------------------------------------------


def test_as005_body_token_count_warning(tmp_path: pathlib.Path):
    """SKILL.md body exceeding TOKEN_WARNING_THRESHOLD tokens produces AS005 warning."""
    import tiktoken

    from skilllint.token_counter import TOKEN_WARNING_THRESHOLD

    skill_dir = tmp_path / "my-skill"
    skill_dir.mkdir()
    skill_md = skill_dir / "SKILL.md"

    # Build body text that exceeds TOKEN_WARNING_THRESHOLD tokens.
    # "word " is 2 tokens (word + space) in cl100k_base; repeat enough times
    # to comfortably exceed the threshold.
    enc = tiktoken.get_encoding("cl100k_base")
    unit = "The quick brown fox jumps over the lazy dog. "
    unit_tokens = len(enc.encode(unit))
    repeats = (TOKEN_WARNING_THRESHOLD // unit_tokens) + 50
    body_text = unit * repeats

    assert len(enc.encode(body_text)) > TOKEN_WARNING_THRESHOLD, (
        "Test setup: body must exceed TOKEN_WARNING_THRESHOLD tokens"
    )

    skill_md.write_text(
        textwrap.dedent("""\
            ---
            name: my-skill
            description: A skill with a very long body that exceeds the token warning threshold.
            ---

        """)
        + body_text
        + "\n"
    )
    violations = check_skill_md(skill_md)
    as005 = _violations_with_code(violations, "AS005")
    assert as005 != [], "Expected AS005 violation when body exceeds TOKEN_WARNING_THRESHOLD tokens"
    assert as005[0].get("severity") in ("warning", "warn", "error"), (
        f"Expected AS005 severity to be warning or error, got: {as005[0].get('severity')}"
    )


# ---------------------------------------------------------------------------
# AS006: eval_queries.json absence info notice
# ---------------------------------------------------------------------------


def test_as006_no_eval_queries_info(tmp_path: pathlib.Path):
    """SKILL.md directory without eval_queries.json produces AS006 info."""
    skill_dir = tmp_path / "my-skill"
    skill_dir.mkdir()
    skill_md = skill_dir / "SKILL.md"
    skill_md.write_text(
        textwrap.dedent("""\
            ---
            name: my-skill
            description: A skill without eval queries.
            ---

            Body content.
        """)
    )
    # No eval_queries.json in skill_dir
    violations = check_skill_md(skill_md)
    as006 = _violations_with_code(violations, "AS006")
    assert as006 != [], "Expected AS006 info when eval_queries.json is absent"
    assert as006[0].get("severity") in ("info", "information"), (
        f"Expected AS006 to be info severity, got: {as006[0].get('severity')}"
    )
