import pytest
from sqlalchemy import func, select
from sqlalchemy.exc import IntegrityError

from backend.app.models import Artist, PatreonSeenMedia, Source

pytestmark = pytest.mark.integration


async def _source(db):
    artist = Artist(name="Seen Ledger Artist", slug="seen-ledger-artist")
    db.add(artist)
    await db.flush()
    source = Source(
        artist_id=artist.id,
        platform="patreon",
        url="https://www.patreon.com/seenledger",
    )
    db.add(source)
    await db.flush()
    return source.id


@pytest.mark.asyncio
async def test_patreon_seen_media_dedup(db):
    source_id = await _source(db)
    db.add(
        PatreonSeenMedia(
            source_id=source_id,
            filehash="0123456789abcdef0123456789abcdef",
            post_id="123456",
        )
    )
    await db.flush()

    seen_at = await db.scalar(
        select(PatreonSeenMedia.seen_at).where(
            PatreonSeenMedia.source_id == source_id
        )
    )
    assert seen_at is not None

    # A second sighting of the same (source_id, filehash) is rejected by the
    # unique constraint. Wrap in a savepoint so the IntegrityError doesn't
    # poison the outer transaction.
    with pytest.raises(IntegrityError):
        async with db.begin_nested():
            db.add(
                PatreonSeenMedia(
                    source_id=source_id,
                    filehash="0123456789abcdef0123456789abcdef",
                    post_id="654321",
                )
            )
            await db.flush()

    # Same filehash but a different post_id sentinel still inserts: the
    # dedup axis is (source_id, filehash), not post_id.
    db.add(
        PatreonSeenMedia(
            source_id=source_id,
            filehash="video:123456:7890",
            post_id="123456",
        )
    )
    await db.flush()

    count = await db.scalar(
        select(func.count(PatreonSeenMedia.id)).where(
            PatreonSeenMedia.source_id == source_id
        )
    )
    assert count == 2
