"""End-to-end route tests for the Spotify login surface."""

from urllib.parse import parse_qs, urlparse

import httpx2
from fastapi.testclient import TestClient

from app.config import AppMode, Settings
from app.main import create_app


def test_login_callback_cookie_and_current_user_flow() -> None:
    async def spotify_handler(request: httpx2.Request) -> httpx2.Response:
        if request.url.host == "accounts.spotify.com":
            return httpx2.Response(
                200,
                json={
                    "access_token": "access",
                    "refresh_token": "refresh",
                    "expires_in": 3600,
                },
            )
        assert request.url == "https://api.spotify.com/v1/me"
        return httpx2.Response(
            200,
            json={"account_id": "stable-account", "display_name": "Ada Listener"},
        )

    app = create_app(
        application_settings=_live_settings(),
        http_transport=httpx2.MockTransport(spotify_handler),
    )
    with TestClient(app, follow_redirects=False) as client:
        unauthenticated_response = client.get("/api/auth/me")
        login_response = client.get("/api/auth/login")

        authorize_url = urlparse(login_response.headers["location"])
        authorize_query = parse_qs(authorize_url.query)
        state = authorize_query["state"][0]

        assert unauthenticated_response.status_code == 401
        assert login_response.status_code == 307
        assert authorize_url.netloc == "accounts.spotify.com"
        assert authorize_url.path == "/authorize"
        assert authorize_query["code_challenge"][0]
        assert authorize_query["code_challenge_method"] == ["S256"]

        callback_response = client.get("/callback", params={"code": "code", "state": state})

        assert callback_response.status_code == 307
        assert callback_response.headers["location"] == "/"
        assert "discovery_session=" in callback_response.headers["set-cookie"]
        assert "HttpOnly" in callback_response.headers["set-cookie"]
        assert "SameSite=lax" in callback_response.headers["set-cookie"]
        assert client.get("/api/auth/me").json() == {"display_name": "Ada Listener"}


def test_unknown_callback_state_redirects_to_login_error() -> None:
    async def spotify_handler(request: httpx2.Request) -> httpx2.Response:
        raise AssertionError("Spotify must not be called for an unknown state")

    app = create_app(
        application_settings=_live_settings(),
        http_transport=httpx2.MockTransport(spotify_handler),
    )
    with TestClient(app, follow_redirects=False) as client:
        response = client.get("/callback", params={"code": "code", "state": "unknown"})

    assert response.status_code == 307
    assert response.headers["location"] == "/?login=error"


def test_spotify_failure_during_callback_redirects_to_login_error() -> None:
    async def spotify_handler(request: httpx2.Request) -> httpx2.Response:
        return httpx2.Response(400)

    app = create_app(
        application_settings=_live_settings(),
        http_transport=httpx2.MockTransport(spotify_handler),
    )
    with TestClient(app, follow_redirects=False) as client:
        login_response = client.get("/api/auth/login")
        authorize_query = parse_qs(urlparse(login_response.headers["location"]).query)
        response = client.get(
            "/callback",
            params={"code": "code", "state": authorize_query["state"][0]},
        )

    assert response.status_code == 307
    assert response.headers["location"] == "/?login=error"


def test_seed_session_authenticates_requests_without_a_cookie() -> None:
    async def spotify_handler(request: httpx2.Request) -> httpx2.Response:
        if request.url.host == "accounts.spotify.com":
            return httpx2.Response(200, json={"access_token": "seed-access", "expires_in": 3600})
        assert request.url.path == "/v1/me"
        return httpx2.Response(200, json={"id": "seed-account", "display_name": "Seed Listener"})

    app = create_app(
        application_settings=Settings(
            app_mode=AppMode.LIVE,
            spotify_client_id="client-id",
            anthropic_api_key="test-key",
            spotify_seed_refresh_token="seed-refresh",
        ),
        http_transport=httpx2.MockTransport(spotify_handler),
    )
    with TestClient(app) as client:
        response = client.get("/api/auth/me")

    assert response.status_code == 200
    assert response.json() == {"display_name": "Seed Listener"}


def test_seed_session_failure_keeps_application_serving() -> None:
    async def spotify_handler(request: httpx2.Request) -> httpx2.Response:
        return httpx2.Response(400)

    app = create_app(
        application_settings=Settings(
            app_mode=AppMode.LIVE,
            spotify_client_id="client-id",
            anthropic_api_key="test-key",
            spotify_seed_refresh_token="seed-refresh",
        ),
        http_transport=httpx2.MockTransport(spotify_handler),
    )
    with TestClient(app, follow_redirects=False) as client:
        health_response = client.get("/api/health")
        login_response = client.get("/api/auth/login")

        assert app.state.seed_session_id is None

    assert health_response.status_code == 200
    assert login_response.status_code == 307


def _live_settings() -> Settings:
    return Settings(
        app_mode=AppMode.LIVE,
        spotify_client_id="client-id",
        anthropic_api_key="test-key",
    )
