import pytest
from auto_archiver.modules.atlos_feeder_db_storage import AtlosFeederDbStorage as AtlosFeeder


class FakeAPIResponse:
    """Simulate a response object."""

    def __init__(self, data: dict, raise_error: bool = False) -> None:
        self._data = data
        self.raise_error = raise_error

    def json(self) -> dict:
        return self._data

    def raise_for_status(self) -> None:
        if self.raise_error:
            raise Exception("HTTP error")


@pytest.fixture
def atlos_feeder(setup_module, mocker) -> AtlosFeeder:
    """Fixture for AtlosFeeder."""
    configs: dict = {
        "api_token": "abc123",
        "atlos_url": "https://platform.atlos.org",
    }
    mocker.patch("requests.Session")
    atlos_feeder = setup_module("atlos_feeder_db_storage", configs)
    fake_session = mocker.MagicMock()
    # Configure the default response to have no results so that __iter__ terminates
    fake_session.get.return_value = FakeAPIResponse({"next": None, "results": []})
    atlos_feeder.session = fake_session
    return atlos_feeder


@pytest.fixture
def mock_atlos_api(atlos_feeder):
    """Fixture to update the atlos_feeder.session.get side_effect."""

    def _mock_responses(responses):
        atlos_feeder.session.get.side_effect = [FakeAPIResponse(data) for data in responses]

    return _mock_responses


def test_atlos_feeder_iter_yields_valid_metadata(atlos_feeder, mock_atlos_api):
    """Test valid items are yielded and invalid ones ignored."""
    mock_atlos_api(
        [
            {
                "next": None,
                "results": [
                    {
                        "source_url": "http://example.com",
                        "id": 1,
                        "metadata": {"auto_archiver": {"processed": False}},
                        "visibility": "visible",
                        "status": "complete",
                    },
                    {
                        "source_url": "",
                        "id": 2,
                        "metadata": {"auto_archiver": {"processed": False}},
                        "visibility": "visible",
                        "status": "complete",
                    },
                    {
                        "source_url": "http://example.org",
                        "id": 3,
                        "metadata": {"auto_archiver": {"processed": True}},
                        "visibility": "visible",
                        "status": "complete",
                    },
                ],
            }
        ]
    )

    items = list(atlos_feeder)
    assert len(items) == 1
    assert items[0].get_url() == "http://example.com"
    assert items[0].get("atlos_id") == 1


def test_atlos_feeder_multiple_pages(atlos_feeder, mock_atlos_api):
    """Test iteration over multiple pages with valid items."""
    mock_atlos_api(
        [
            {
                "next": "cursor2",
                "results": [
                    {
                        "source_url": "http://example1.com",
                        "id": 10,
                        "metadata": {"auto_archiver": {"processed": False}},
                        "visibility": "visible",
                        "status": "complete",
                    },
                ],
            },
            {
                "next": None,
                "results": [
                    {
                        "source_url": "http://example2.com",
                        "id": 20,
                        "metadata": {"auto_archiver": {"processed": False}},
                        "visibility": "visible",
                        "status": "complete",
                    },
                ],
            },
        ]
    )

    items = list(atlos_feeder)
    assert len(items) == 2
    assert items[0].get_url() == "http://example1.com"
    assert items[0].get("atlos_id") == 10
    assert items[1].get_url() == "http://example2.com"
    assert items[1].get("atlos_id") == 20


def test_atlos_feeder_no_results(atlos_feeder, mock_atlos_api):
    """Test iteration stops when no results are returned."""
    mock_atlos_api([{"next": None, "results": []}])
    assert list(atlos_feeder) == []


def test_atlos_feeder_http_error(atlos_feeder, mocker):
    """Test raises an exception on HTTP error."""
    fake_response = FakeAPIResponse({"next": None, "results": []}, raise_error=True)
    atlos_feeder.session.get.side_effect = [fake_response]
    with pytest.raises(Exception, match="HTTP error"):
        list(atlos_feeder)
