"""Unit tests for axm_bib.hooks — ParseBibAction for protocol context injection."""

from __future__ import annotations

from pathlib import Path

from axm_bib.hooks import ParseBibAction

SAMPLE_BIB = """\
@article{smith2024deep,
  title    = {Deep Learning for Citation Analysis},
  author   = {John Smith and Jane Doe},
  year     = {2024},
  doi      = {10.1234/test.5678},
  journal  = {Journal of AI},
}
"""

SAMPLE_BIB_NO_DOI = """\
@inproceedings{workshop2024,
  title  = {Workshop Paper on Graphs},
  author = {Alice Müller},
  year   = {2023},
}
"""


class TestParseBibSuccess:
    """ParseBibAction happy-path tests."""

    def test_parse_bib_success(self, tmp_path: Path) -> None:
        """Returns HookResult.ok() with all 5 fields."""
        bib_file = tmp_path / "paper.bib"
        bib_file.write_text(SAMPLE_BIB)

        action = ParseBibAction()
        result = action.execute(
            context={},
            source=str(bib_file),
        )

        assert result.success is True
        assert result.error is None
        assert result.metadata["paper_title"] == "Deep Learning for Citation Analysis"
        assert result.metadata["paper_authors"] == "John Smith, Jane Doe"
        assert result.metadata["paper_doi"] == "10.1234/test.5678"
        assert result.metadata["paper_year"] == 2024
        assert result.metadata["paper_bibtex_key"] == "smith2024deep"

    def test_parse_bib_filtered_inject(self, tmp_path: Path) -> None:
        """inject param filters which fields are returned."""
        bib_file = tmp_path / "paper.bib"
        bib_file.write_text(SAMPLE_BIB)

        action = ParseBibAction()
        result = action.execute(
            context={},
            source=str(bib_file),
            inject=["paper_title", "paper_doi"],
        )

        assert result.success is True
        assert set(result.metadata.keys()) == {"paper_title", "paper_doi"}
        assert result.metadata["paper_title"] == "Deep Learning for Citation Analysis"
        assert result.metadata["paper_doi"] == "10.1234/test.5678"


class TestParseBibErrors:
    """ParseBibAction error-handling tests."""

    def test_parse_bib_file_not_found(self) -> None:
        """Non-existent path returns HookResult.fail()."""
        action = ParseBibAction()
        result = action.execute(
            context={},
            source="/nonexistent/path/paper.bib",
        )

        assert result.success is False
        assert result.error is not None
        assert "not found" in result.error.lower()

    def test_parse_bib_empty_file(self, tmp_path: Path) -> None:
        """Empty .bib file returns HookResult.fail()."""
        bib_file = tmp_path / "empty.bib"
        bib_file.write_text("")

        action = ParseBibAction()
        result = action.execute(
            context={},
            source=str(bib_file),
        )

        assert result.success is False
        assert result.error is not None
        assert "no entries" in result.error.lower()


class TestParseBibContextInterpolation:
    """Context interpolation tests."""

    def test_parse_bib_context_interpolation(self, tmp_path: Path) -> None:
        """source path supports {paper_path} interpolation from context."""
        sub = tmp_path / "papers" / "smith2024"
        sub.mkdir(parents=True)
        bib_file = sub / "paper.bib"
        bib_file.write_text(SAMPLE_BIB)

        action = ParseBibAction()
        result = action.execute(
            context={"paper_path": str(sub)},
            source="{paper_path}/paper.bib",
        )

        assert result.success is True
        assert result.metadata["paper_bibtex_key"] == "smith2024deep"


class TestParseBibEdgeCases:
    """Edge case tests."""

    def test_parse_bib_multiple_entries(self, tmp_path: Path) -> None:
        """Multiple entries in .bib file → uses first entry."""
        multi_bib = SAMPLE_BIB + "\n" + SAMPLE_BIB_NO_DOI
        bib_file = tmp_path / "multi.bib"
        bib_file.write_text(multi_bib)

        action = ParseBibAction()
        result = action.execute(context={}, source=str(bib_file))

        assert result.success is True
        assert result.metadata["paper_bibtex_key"] == "smith2024deep"

    def test_parse_bib_missing_doi(self, tmp_path: Path) -> None:
        """Entry without DOI → paper_doi is None."""
        bib_file = tmp_path / "no_doi.bib"
        bib_file.write_text(SAMPLE_BIB_NO_DOI)

        action = ParseBibAction()
        result = action.execute(context={}, source=str(bib_file))

        assert result.success is True
        assert result.metadata["paper_doi"] is None

    def test_parse_bib_unicode_authors(self, tmp_path: Path) -> None:
        """Authors with diacritics are preserved correctly."""
        bib_file = tmp_path / "unicode.bib"
        bib_file.write_text(SAMPLE_BIB_NO_DOI)

        action = ParseBibAction()
        result = action.execute(context={}, source=str(bib_file))

        assert result.success is True
        assert "Müller" in result.metadata["paper_authors"]
