import pytest

from django.contrib.auth import get_user_model
from scrobbles.models import Scrobble

from people.models import Person, PersonScrobble

User = get_user_model()


@pytest.mark.django_db
def test_signal_creates_person_scrobble_on_save_with_people_ids():
    creator = User.objects.create_user(username="creator", password="testpass123")
    other_user = User.objects.create_user(username="other", password="testpass123")
    person = Person.objects.create(name="Alice", created_by=creator, user=creator)

    scrobble = Scrobble.objects.create(
        user=other_user,
        log={"with_people_ids": [person.id]},
    )

    assert PersonScrobble.objects.filter(person=person, user=other_user).count() == 1


@pytest.mark.django_db
def test_signal_creates_person_scrobble_on_save_with_players():
    creator = User.objects.create_user(username="creator", password="testpass123")
    other_user = User.objects.create_user(username="other", password="testpass123")
    person = Person.objects.create(name="Bob", created_by=creator, user=creator)

    scrobble = Scrobble.objects.create(
        user=other_user,
        log={
            "players": [
                {"person_id": person.id, "win": True, "rank": 1},
            ]
        },
    )

    assert PersonScrobble.objects.filter(person=person, user=other_user).count() == 1


@pytest.mark.django_db
def test_signal_removes_person_scrobble_when_person_removed_from_with_people_ids():
    creator = User.objects.create_user(username="creator", password="testpass123")
    other_user = User.objects.create_user(username="other", password="testpass123")
    person = Person.objects.create(name="Charlie", created_by=creator, user=creator)

    scrobble = Scrobble.objects.create(
        user=other_user,
        log={"with_people_ids": [person.id]},
    )
    assert PersonScrobble.objects.filter(person=person).count() == 1

    scrobble.log = {}
    scrobble.save()

    assert PersonScrobble.objects.filter(person=person).count() == 0


@pytest.mark.django_db
def test_signal_removes_person_scrobble_when_person_removed_from_players():
    creator = User.objects.create_user(username="creator", password="testpass123")
    other_user = User.objects.create_user(username="other", password="testpass123")
    person = Person.objects.create(name="Diana", created_by=creator, user=creator)

    scrobble = Scrobble.objects.create(
        user=other_user,
        log={
            "players": [
                {"person_id": person.id, "win": True, "rank": 1},
            ]
        },
    )
    assert PersonScrobble.objects.filter(person=person).count() == 1

    scrobble.log = {"players": []}
    scrobble.save()

    assert PersonScrobble.objects.filter(person=person).count() == 0


@pytest.mark.django_db
def test_signal_deletes_person_scrobble_on_scrobble_delete():
    creator = User.objects.create_user(username="creator", password="testpass123")
    other_user = User.objects.create_user(username="other", password="testpass123")
    person = Person.objects.create(name="Eve", created_by=creator, user=creator)

    scrobble = Scrobble.objects.create(
        user=other_user,
        log={"with_people_ids": [person.id]},
    )
    assert PersonScrobble.objects.filter(person=person).count() == 1

    scrobble.delete()

    assert PersonScrobble.objects.filter(person=person).count() == 0


@pytest.mark.django_db
def test_signal_skips_when_person_user_matches_scrobble_user():
    user = User.objects.create_user(username="testuser", password="testpass123")
    person = Person.objects.create(name="Frank", created_by=user, user=user)

    scrobble = Scrobble.objects.create(
        user=user,
        log={"with_people_ids": [person.id]},
    )

    assert PersonScrobble.objects.filter(person=person).count() == 0


@pytest.mark.django_db
def test_signal_works_with_different_users():
    user1 = User.objects.create_user(username="user1", password="testpass123")
    user2 = User.objects.create_user(username="user2", password="testpass123")
    person = Person.objects.create(name="Grace", created_by=user1, user=user1)

    scrobble1 = Scrobble.objects.create(
        user=user1,
        log={"with_people_ids": [person.id]},
    )
    scrobble2 = Scrobble.objects.create(
        user=user2,
        log={"with_people_ids": [person.id]},
    )

    assert PersonScrobble.objects.filter(person=person, user=user1).count() == 0
    assert PersonScrobble.objects.filter(person=person, user=user2).count() == 1


@pytest.mark.django_db
def test_person_get_scrobble_count():
    creator = User.objects.create_user(username="creator", password="testpass123")
    other_user = User.objects.create_user(username="other", password="testpass123")
    person = Person.objects.create(name="Henry", created_by=creator, user=creator)

    Scrobble.objects.create(user=other_user, log={"with_people_ids": [person.id]})
    Scrobble.objects.create(user=other_user, log={"with_people_ids": [person.id]})
    Scrobble.objects.create(user=other_user, log={})

    assert person.get_scrobble_count(user=other_user) == 2


@pytest.mark.django_db
def test_person_get_scrobbles():
    creator = User.objects.create_user(username="creator", password="testpass123")
    other_user = User.objects.create_user(username="other", password="testpass123")
    person = Person.objects.create(name="Iris", created_by=creator, user=creator)

    scrobble1 = Scrobble.objects.create(
        user=other_user, log={"with_people_ids": [person.id]}
    )
    scrobble2 = Scrobble.objects.create(
        user=other_user, log={"with_people_ids": [person.id]}
    )
    Scrobble.objects.create(user=other_user, log={})

    scrobbles = person.get_scrobbles(user=other_user)

    assert scrobbles.count() == 2
    assert scrobble1 in scrobbles
    assert scrobble2 in scrobbles


@pytest.mark.django_db
def test_person_scrobble_unique_together():
    creator = User.objects.create_user(username="creator", password="testpass123")
    other_user = User.objects.create_user(username="other", password="testpass123")
    person = Person.objects.create(name="Jack", created_by=creator, user=creator)

    scrobble = Scrobble.objects.create(
        user=other_user,
        log={
            "with_people_ids": [person.id],
            "players": [{"person_id": person.id}],
        },
    )

    assert PersonScrobble.objects.filter(person=person, scrobble=scrobble).count() == 1
