import datetime

import pytest
from django.contrib.auth import get_user_model
from django.utils import timezone

from charts.models import ChartRecord
from charts.utils import build_charts

User = get_user_model()


@pytest.fixture
def user(db):
    return User.objects.create_user(username="charttester", password="testpass123")


@pytest.fixture
def scrobble_data(user, db):
    from scrobbles.models import Scrobble
    from music.models import Track, Artist, Album

    artist = Artist.objects.create(name="Test Artist")
    album = Album.objects.create(name="Test Album", album_artist=artist)
    track = Track.objects.create(title="Test Track", artist=artist, album=album)

    return {
        "user": user,
        "track": track,
    }


@pytest.mark.django_db
def test_build_daily_charts_creates_daily_record(user, scrobble_data):
    from scrobbles.models import Scrobble

    Scrobble.objects.create(
        user=user,
        track=scrobble_data["track"],
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 10, 0)),
    )

    build_charts(user, year=2024, month=3, day=15)

    daily = ChartRecord.objects.filter(
        user=user,
        year=2024,
        month=3,
        day=15,
        week__isnull=True,
        track__isnull=False,
    )
    assert daily.exists()
    assert daily.first().track == scrobble_data["track"]


@pytest.mark.django_db
def test_build_monthly_charts_creates_monthly_record(user, scrobble_data):
    from scrobbles.models import Scrobble

    Scrobble.objects.create(
        user=user,
        track=scrobble_data["track"],
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 10, 0)),
    )

    build_charts(user, year=2024, month=3)

    monthly = ChartRecord.objects.filter(
        user=user,
        year=2024,
        month=3,
        week__isnull=True,
        day__isnull=True,
        track__isnull=False,
    )
    assert monthly.exists()
    assert monthly.first().track == scrobble_data["track"]


@pytest.mark.django_db
def test_build_weekly_charts_creates_weekly_record(user, scrobble_data):
    from scrobbles.models import Scrobble

    Scrobble.objects.create(
        user=user,
        track=scrobble_data["track"],
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 10, 0)),
    )

    build_charts(user, year=2024, week=11)

    weekly = ChartRecord.objects.filter(
        user=user,
        year=2024,
        week=11,
        month__isnull=True,
        day__isnull=True,
        track__isnull=False,
    )
    assert weekly.exists()
    assert weekly.first().track == scrobble_data["track"]


@pytest.mark.django_db
def test_build_yearly_charts_creates_yearly_record(user, scrobble_data):
    from scrobbles.models import Scrobble

    Scrobble.objects.create(
        user=user,
        track=scrobble_data["track"],
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 10, 0)),
    )

    build_charts(user, year=2024)

    yearly = ChartRecord.objects.filter(
        user=user,
        year=2024,
        month__isnull=True,
        week__isnull=True,
        day__isnull=True,
        track__isnull=False,
    )
    assert yearly.exists()
    assert yearly.first().track == scrobble_data["track"]


@pytest.mark.django_db
def test_build_charts_ranks_by_count(user, scrobble_data):
    from scrobbles.models import Scrobble
    from music.models import Track, Artist

    track1 = scrobble_data["track"]
    track2 = Track.objects.create(
        title="Test Track 2",
        artist=track1.artist,
        album=track1.album,
    )

    Scrobble.objects.create(
        user=user,
        track=track1,
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 10, 0)),
    )
    Scrobble.objects.create(
        user=user,
        track=track1,
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 11, 0)),
    )
    Scrobble.objects.create(
        user=user,
        track=track2,
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 12, 0)),
    )

    build_charts(user, year=2024, month=3, day=15)

    daily = ChartRecord.objects.filter(
        user=user,
        year=2024,
        month=3,
        day=15,
        track__isnull=False,
    ).order_by("rank")

    assert daily.count() == 2
    assert daily[0].track == track1
    assert daily[0].rank == 1
    assert daily[0].count == 2
    assert daily[1].track == track2
    assert daily[1].rank == 2
    assert daily[1].count == 1


@pytest.mark.django_db
def test_build_daily_charts_deletes_existing_daily_record(user, scrobble_data):
    from scrobbles.models import Scrobble
    from music.models import Track, Artist

    track1 = scrobble_data["track"]
    track2 = Track.objects.create(
        title="Test Track 2",
        artist=track1.artist,
        album=track1.album,
    )

    Scrobble.objects.create(
        user=user,
        track=track1,
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 10, 0)),
    )

    build_charts(user, year=2024, month=3, day=15)
    assert ChartRecord.objects.filter(
        user=user, year=2024, month=3, day=15, track=track1
    ).exists()

    Scrobble.objects.create(
        user=user,
        track=track2,
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 11, 0)),
    )

    build_charts(user, year=2024, month=3, day=15)

    daily = ChartRecord.objects.filter(
        user=user,
        year=2024,
        month=3,
        day=15,
        track__isnull=False,
    )
    assert daily.count() == 2
    assert daily.filter(track=track1).exists()
    assert daily.filter(track=track2).exists()


@pytest.mark.django_db
def test_build_monthly_charts_deletes_existing_monthly_record(user, scrobble_data):
    from scrobbles.models import Scrobble
    from music.models import Track, Artist

    track1 = scrobble_data["track"]
    track2 = Track.objects.create(
        title="Test Track 2",
        artist=track1.artist,
        album=track1.album,
    )

    Scrobble.objects.create(
        user=user,
        track=track1,
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 15, 10, 0)),
    )

    build_charts(user, year=2024, month=3)

    ChartRecord.objects.filter(user=user, year=2024, month=3, track=track1).delete()

    Scrobble.objects.create(
        user=user,
        track=track2,
        played_to_completion=True,
        timestamp=timezone.make_aware(datetime.datetime(2024, 3, 16, 11, 0)),
    )

    build_charts(user, year=2024, month=3)

    monthly = ChartRecord.objects.filter(
        user=user,
        year=2024,
        month=3,
        week__isnull=True,
        day__isnull=True,
        track__isnull=False,
    )
    assert monthly.count() == 2
