from __future__ import annotations

import pytest

import v1.auth.gateway as auth_gateway_module
from v1.auth.schemas import (
    AuthUser,
    SessionCreateRequest,
    SessionRefreshRequest,
    SessionResponse,
    UserByEmailResponse,
    VerificationCreateRequest,
    VerificationCreateResponse,
    VerificationResendRequest,
    VerificationVerifyRequest,
)
from v1.auth.service import AuthService, AuthServiceGateway


class FakeGateway(AuthServiceGateway):
    def __init__(self, response: SessionResponse) -> None:
        self._response = response

    async def create_verification(
        self, request: VerificationCreateRequest
    ) -> VerificationCreateResponse:
        return VerificationCreateResponse(email=request.email)

    async def verify_verification(
        self, request: VerificationVerifyRequest
    ) -> SessionResponse:
        return self._response

    async def resend_verification(self, request: VerificationResendRequest) -> None:
        return None

    async def create_session(self, request: SessionCreateRequest) -> SessionResponse:
        return self._response

    async def refresh_session(self, request: SessionRefreshRequest) -> SessionResponse:
        return self._response

    async def delete_session(self, refresh_token: str | None) -> None:
        return None

    async def get_user_by_email(self, email: str) -> UserByEmailResponse:
        return UserByEmailResponse(
            id="user-1",
            email=email,
            created_at="2026-02-24T00:00:00Z",
            email_confirmed_at=None,
        )


@pytest.mark.asyncio
async def test_signup_maps_response() -> None:
    user = AuthUser(id="user-1", email="user@example.com")
    token_response = SessionResponse(
        access_token="access",
        refresh_token="refresh",
        expires_in=3600,
        token_type="bearer",
        user=user,
    )
    service = AuthService(gateway=FakeGateway(token_response))

    start_result = await service.create_verification(
        VerificationCreateRequest(
            username="demo", email="user@example.com", password="secret123"
        )
    )
    assert start_result.email == "user@example.com"

    result = await service.verify_verification(
        VerificationVerifyRequest(email="user@example.com", token="123456")
    )

    assert result.access_token == "access"
    assert result.refresh_token == "refresh"
    assert result.user.id == "user-1"


class LogoutAssertingGateway(AuthServiceGateway):
    def __init__(self, expected_refresh_token: str) -> None:
        self._expected_refresh_token = expected_refresh_token

    async def create_verification(
        self, request: VerificationCreateRequest
    ) -> VerificationCreateResponse:
        raise NotImplementedError

    async def verify_verification(
        self, request: VerificationVerifyRequest
    ) -> SessionResponse:
        raise NotImplementedError

    async def resend_verification(self, request: VerificationResendRequest) -> None:
        raise NotImplementedError

    async def create_session(self, request: SessionCreateRequest) -> SessionResponse:
        raise NotImplementedError

    async def refresh_session(self, request: SessionRefreshRequest) -> SessionResponse:
        raise NotImplementedError

    async def delete_session(self, refresh_token: str | None) -> None:
        assert refresh_token == self._expected_refresh_token

    async def get_user_by_email(self, email: str) -> UserByEmailResponse:
        raise NotImplementedError


@pytest.mark.asyncio
async def test_logout_forwards_refresh_token() -> None:
    service = AuthService(gateway=LogoutAssertingGateway("refresh-token"))

    await service.delete_session("refresh-token")


@pytest.mark.asyncio
async def test_get_user_by_email_forwards_to_gateway() -> None:
    user = AuthUser(id="user-1", email="user@example.com")
    token_response = SessionResponse(
        access_token="access",
        refresh_token="refresh",
        expires_in=3600,
        token_type="bearer",
        user=user,
    )
    service = AuthService(gateway=FakeGateway(token_response))

    result = await service.get_user_by_email("user@example.com")

    assert result.email == "user@example.com"


@pytest.mark.asyncio
async def test_signup_resend_returns_none() -> None:
    user = AuthUser(id="user-1", email="user@example.com")
    token_response = SessionResponse(
        access_token="access",
        refresh_token="refresh",
        expires_in=3600,
        token_type="bearer",
        user=user,
    )
    service = AuthService(gateway=FakeGateway(token_response))

    result = await service.resend_verification(
        VerificationResendRequest(email="user@example.com")
    )

    assert result is None


@pytest.mark.asyncio
async def test_supabase_signup_passes_username_in_metadata(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    captured_payload: dict[str, object] = {}

    class FakeSupabaseAuth:
        def sign_up(self, payload: dict[str, object]) -> object:
            captured_payload.update(payload)

            class _User:
                id = "user-1"
                email = "user@example.com"

            class _Session:
                access_token = "access"
                refresh_token = "refresh"
                expires_in = 3600
                token_type = "bearer"

            class _Response:
                user = _User()
                session = None

            return _Response()

    class FakeClient:
        auth = FakeSupabaseAuth()

    monkeypatch.setattr(auth_gateway_module, "create_client", lambda *_: FakeClient())

    gateway = auth_gateway_module.SupabaseAuthGateway()
    await gateway.create_verification(
        VerificationCreateRequest(
            username="demo",
            email="user@example.com",
            password="secret123",
        )
    )

    assert captured_payload["data"] == {"username": "demo"}
