"""Functional tests for BibSearchTool."""

from __future__ import annotations

from unittest.mock import MagicMock, patch

from axm.tools.base import ToolResult

from axm_bib.models import Paper
from axm_bib.tools.bib_search import BibSearchTool
from tests.conftest import SAMPLE_DOI


class TestBibSearchTool:
    """BibSearchTool E2E (mocked HTTP)."""

    def test_name_property(self) -> None:
        """Tool name is 'bib_search'."""
        tool = BibSearchTool()
        assert tool.name == "bib_search"

    @patch("axm_bib.tools.bib_search.BibPipeline")
    def test_execute_returns_tool_result(self, mock_pipeline_class: MagicMock) -> None:
        """execute() returns a ToolResult."""
        mock_pipeline = mock_pipeline_class.return_value
        mock_pipeline.search.return_value = [
            Paper(
                title="Deep Learning",
                authors=["Smith"],
                year=2024,
                doi=SAMPLE_DOI,
                source="semantic_scholar",
            )
        ]

        tool = BibSearchTool()
        result = tool.execute(query="Deep Learning", limit=5)
        assert isinstance(result, ToolResult)
        assert result.success is True

    @patch("axm_bib.tools.bib_search.BibPipeline")
    def test_execute_success_data_shape(self, mock_pipeline_class: MagicMock) -> None:
        """result.data['papers'] is a list of dicts with expected keys."""
        mock_pipeline = mock_pipeline_class.return_value
        mock_pipeline.search.return_value = [
            Paper(
                title="Deep Learning",
                authors=["Smith"],
                year=2024,
                doi=SAMPLE_DOI,
                source="semantic_scholar",
            )
        ]

        tool = BibSearchTool()
        result = tool.execute(query="Deep Learning")
        assert "papers" in result.data
        assert isinstance(result.data["papers"], list)
        assert len(result.data["papers"]) == 1
        paper = result.data["papers"][0]
        assert "title" in paper
        assert "doi" in paper

    @patch("axm_bib.tools.bib_search.BibPipeline")
    def test_execute_empty_query(self, mock_pipeline_class: MagicMock) -> None:
        """Empty query returns success with empty papers list."""
        mock_pipeline = mock_pipeline_class.return_value
        mock_pipeline.search.return_value = []

        tool = BibSearchTool()
        result = tool.execute(query="")
        assert result.success is True
        assert result.data["papers"] == []

    @patch("axm_bib.tools.bib_search.BibPipeline")
    def test_execute_api_failure(self, mock_pipeline_class: MagicMock) -> None:
        """API failure → success=False, error set."""
        mock_pipeline = mock_pipeline_class.return_value
        mock_pipeline.search.side_effect = Exception("Network error")

        tool = BibSearchTool()
        result = tool.execute(query="Deep Learning")
        assert result.success is False
        assert result.error is not None
        assert "Network error" in result.error

    def test_execute_invalid_limit(self) -> None:
        """Negative limit → success=False with error."""
        tool = BibSearchTool()
        result = tool.execute(query="test", limit=-1)
        assert result.success is False
        assert result.error is not None
        assert "limit" in result.error.lower()
