"""Unit tests for the pure-stdlib parsers module (#82 Phase 1).

These tests depend only on `:parsers` so they re-run only when
parsers.py itself changes — handler edits in server.py do not
invalidate them.
"""
from __future__ import annotations

import pytest

from active_claude_github_mcp.parsers import (
    parse_changelog,
    parse_owner_repo,
    parse_skill_version,
    semver_gt,
)


class TestParseSkillVersion:
    def test_finds_header(self):
        content = "# active-claude-github\n**Version:** 1.2.3\n\n..."
        assert parse_skill_version(content) == "1.2.3"

    def test_two_component_version(self):
        # "1.2" is accepted as 1.2 (regex tolerates X.Y)
        content = "**Version:** 1.2\n"
        assert parse_skill_version(content) == "1.2"

    def test_returns_none_on_missing_header(self):
        assert parse_skill_version("# some file with no version\n") is None

    def test_returns_none_on_empty(self):
        assert parse_skill_version("") is None


class TestParseChangelog:
    def test_single_entry(self):
        content = (
            "## Changelog\n"
            "- **1.0.0** (2026-04-21) — Initial release.\n"
            "\n## Trigger\n"
        )
        entries = parse_changelog(content)
        assert len(entries) == 1
        assert entries[0] == {
            "version": "1.0.0",
            "date": "2026-04-21",
            "summary": "Initial release.",
        }

    def test_multiple_entries_multi_line(self):
        content = (
            "## Changelog\n"
            "- **1.1.0** (2026-04-23) — MCP-native rewrite. "
            "Includes session lifecycle, recording, and TOC.\n"
            "- **1.0.1** (2026-04-23) — Bootstrap bug-fix batch.\n"
            "- **1.0.0** (2026-04-21) — Initial release.\n"
            "\n## Something Else\n"
        )
        entries = parse_changelog(content)
        assert [e["version"] for e in entries] == ["1.1.0", "1.0.1", "1.0.0"]
        assert "MCP-native rewrite" in entries[0]["summary"]

    def test_returns_empty_when_no_section(self):
        assert parse_changelog("no changelog here") == []

    def test_returns_empty_on_empty_input(self):
        assert parse_changelog("") == []


class TestSemverGt:
    def test_greater(self):
        assert semver_gt("1.2.0", "1.1.0")
        assert semver_gt("2.0.0", "1.9.9")
        assert semver_gt("1.0.1", "1.0.0")

    def test_equal_is_not_greater(self):
        assert not semver_gt("1.0.0", "1.0.0")

    def test_less_is_not_greater(self):
        assert not semver_gt("1.0.0", "1.0.1")
        assert not semver_gt("1.0.0", "2.0.0")

    def test_missing_components_treated_as_zero(self):
        # "1.2" == "1.2.0" per padding
        assert not semver_gt("1.2", "1.2.0")
        assert semver_gt("1.2.1", "1.2")


class TestParseOwnerRepo:
    def test_valid(self):
        owner, repo = parse_owner_repo("telejester/claude-skills-dev")
        assert owner == "telejester"
        assert repo == "claude-skills-dev"

    def test_no_slash_raises(self):
        with pytest.raises(ValueError, match="owner/repo"):
            parse_owner_repo("noslash")

    def test_empty_owner_raises(self):
        with pytest.raises(ValueError, match="owner/repo"):
            parse_owner_repo("/repo")

    def test_empty_repo_raises(self):
        with pytest.raises(ValueError, match="owner/repo"):
            parse_owner_repo("owner/")

    def test_too_many_slashes_raises(self):
        with pytest.raises(ValueError, match="owner/repo"):
            parse_owner_repo("owner/repo/extra")


if __name__ == "__main__":
    import sys
    sys.exit(pytest.main([__file__, "-v"]))
