import httpx
import pytest
import respx
from sqlalchemy import func
from sqlalchemy import select
from sqlalchemy.orm import Session

from app import models
from app.actor import fetch_actor
from app.database import AsyncSession
from tests import factories


@pytest.mark.asyncio
async def test_fetch_actor(async_db_session: AsyncSession, respx_mock) -> None:
    # Given a remote actor
    ra = factories.RemoteActorFactory(
        base_url="https://example.com",
        username="toto",
        public_key="pk",
    )
    respx_mock.get(ra.ap_id).mock(return_value=httpx.Response(200, json=ra.ap_actor))

    # When fetching this actor for the first time
    saved_actor = await fetch_actor(async_db_session, ra.ap_id)

    # Then it has been fetched and saved in DB
    assert respx.calls.call_count == 1
    assert (
        await async_db_session.execute(select(models.Actor))
    ).scalar_one().ap_id == saved_actor.ap_id

    # When fetching it a second time
    actor_from_db = await fetch_actor(async_db_session, ra.ap_id)

    # Then it's read from the DB
    assert actor_from_db.ap_id == ra.ap_id
    assert (
        await async_db_session.execute(select(func.count(models.Actor.id)))
    ).scalar_one() == 1
    assert respx.calls.call_count == 1


def test_sqlalchemy_factory(db: Session) -> None:
    ra = factories.RemoteActorFactory(
        base_url="https://example.com",
        username="toto",
        public_key="pk",
    )
    actor_in_db = factories.ActorFactory(
        ap_type=ra.ap_type,
        ap_actor=ra.ap_actor,
        ap_id=ra.ap_id,
    )
    assert actor_in_db.id == db.execute(select(models.Actor)).scalar_one().id