import pytest
from unittest.mock import AsyncMock, MagicMock, call

from api.v1.schemas.settings import (
    LastFmConnectionSettings,
    ListenBrainzConnectionSettings,
    PrimaryMusicSourceSettings,
)
from services.home_charts_service import HomeChartsService


def _make_prefs(
    lb_enabled: bool = True,
    lfm_enabled: bool = True,
    lfm_username: str = "lfmuser",
    primary_source: str = "lastfm",
) -> MagicMock:
    prefs = MagicMock()
    lb_settings = ListenBrainzConnectionSettings(
        user_token="tok", username="lbuser", enabled=lb_enabled
    )
    prefs.get_listenbrainz_connection.return_value = lb_settings

    lfm_settings = LastFmConnectionSettings(
        api_key="key",
        shared_secret="secret",
        session_key="sk",
        username=lfm_username,
        enabled=lfm_enabled,
    )
    prefs.get_lastfm_connection.return_value = lfm_settings
    prefs.is_lastfm_enabled.return_value = lfm_enabled
    prefs.get_primary_music_source.return_value = PrimaryMusicSourceSettings(source=primary_source)
    return prefs


def _make_service(
    lb_enabled: bool = True,
    lfm_enabled: bool = True,
    lfm_username: str = "lfmuser",
    primary_source: str = "lastfm",
) -> tuple[HomeChartsService, AsyncMock, AsyncMock]:
    lb_repo = AsyncMock()
    lb_repo.get_sitewide_top_artists = AsyncMock(return_value=[])
    lb_repo.get_sitewide_top_release_groups = AsyncMock(return_value=[])

    lfm_repo = AsyncMock()
    lfm_repo.get_global_top_artists = AsyncMock(return_value=[])
    lfm_repo.get_user_top_albums = AsyncMock(return_value=[])

    lidarr_repo = AsyncMock()
    lidarr_repo.get_library = AsyncMock(return_value=[])
    lidarr_repo.get_artists_from_library = AsyncMock(return_value=[])

    mb_repo = AsyncMock()
    prefs = _make_prefs(
        lb_enabled=lb_enabled,
        lfm_enabled=lfm_enabled,
        lfm_username=lfm_username,
        primary_source=primary_source,
    )

    service = HomeChartsService(
        listenbrainz_repo=lb_repo,
        lidarr_repo=lidarr_repo,
        musicbrainz_repo=mb_repo,
        lastfm_repo=lfm_repo,
        preferences_service=prefs,
    )
    return service, lb_repo, lfm_repo


class TestPopularAlbumsLastFmMissingUsername:
    @pytest.mark.asyncio
    async def test_returns_empty_when_username_missing(self):
        """When Last.fm is enabled but username is empty, should return empty response."""
        service, _, lfm_repo = _make_service(
            lfm_enabled=True, lfm_username="", primary_source="lastfm"
        )
        result = await service.get_popular_albums(limit=10, source="lastfm")
        lfm_repo.get_user_top_albums.assert_not_awaited()
        assert result.all_time.featured is None
        assert result.all_time.items == []
        assert result.all_time.total_count == 0

    @pytest.mark.asyncio
    async def test_returns_empty_when_lastfm_disabled(self):
        """When Last.fm is disabled, should return empty response."""
        service, _, lfm_repo = _make_service(
            lfm_enabled=False, lfm_username="user", primary_source="lastfm"
        )
        result = await service._get_popular_albums_lastfm(limit=10)
        lfm_repo.get_user_top_albums.assert_not_awaited()
        assert result.all_time.total_count == 0

    @pytest.mark.asyncio
    async def test_calls_api_when_username_present(self):
        """When Last.fm is enabled with a username, should call the API."""
        service, _, lfm_repo = _make_service(
            lfm_enabled=True, lfm_username="validuser", primary_source="lastfm"
        )
        await service.get_popular_albums(limit=10, source="lastfm")
        assert lfm_repo.get_user_top_albums.await_count == 4
        lfm_repo.get_user_top_albums.assert_has_awaits(
            [
                call("validuser", period="7day", limit=11),
                call("validuser", period="1month", limit=11),
                call("validuser", period="12month", limit=11),
                call("validuser", period="overall", limit=11),
            ],
            any_order=True,
        )

    @pytest.mark.asyncio
    async def test_range_endpoint_uses_source_specific_lastfm_period(self):
        service, _, lfm_repo = _make_service(
            lfm_enabled=True, lfm_username="validuser", primary_source="lastfm"
        )
        await service.get_popular_albums_by_range(
            range_key="this_year",
            limit=5,
            offset=0,
            source="lastfm",
        )
        lfm_repo.get_user_top_albums.assert_awaited_once_with(
            "validuser", period="12month", limit=6
        )
