import json

import pytest
from django.urls import reverse

from funkwhale_api.favorites import serializers
from funkwhale_api.favorites.models import TrackFavorite


def test_user_can_add_favorite(factories):
    track = factories["music.Track"]()
    user = factories["users.User"](with_actor=True)
    f = TrackFavorite.add(track, user.actor)

    assert f.track == track
    assert f.actor.user == user


def test_user_can_get_his_favorites(
    api_request, factories, logged_in_api_client, client
):
    request = api_request.get("/")
    logged_in_api_client.user.create_actor()
    favorite = factories["favorites.TrackFavorite"](
        actor=logged_in_api_client.user.actor
    )
    factories["favorites.TrackFavorite"]()
    url = reverse("api:v1:favorites:tracks-list")
    response = logged_in_api_client.get(url, {"scope": "me"})
    expected = [
        serializers.UserTrackFavoriteSerializer(
            favorite, context={"request": request}
        ).data
    ]

    assert response.status_code == 200
    assert response.data["results"] == expected


def test_user_can_retrieve_all_favorites_at_once(
    api_request, factories, logged_in_api_client, client
):
    logged_in_api_client.user.create_actor()
    favorite = factories["favorites.TrackFavorite"](
        actor=logged_in_api_client.user.actor
    )
    factories["favorites.TrackFavorite"]()
    url = reverse("api:v1:favorites:tracks-all")
    response = logged_in_api_client.get(url, {"user": logged_in_api_client.user.pk})
    expected = [{"track": favorite.track.id, "id": favorite.id}]
    assert response.status_code == 200
    assert response.data["results"] == expected


def test_user_can_add_favorite_via_api(factories, logged_in_api_client, activity_muted):
    track = factories["music.Track"]()
    logged_in_api_client.user.create_actor()

    url = reverse("api:v1:favorites:tracks-list")
    response = logged_in_api_client.post(url, {"track": track.pk})

    favorite = TrackFavorite.objects.latest("id")
    expected = {
        "track": track.pk,
        "id": favorite.id,
        "creation_date": favorite.creation_date.isoformat().replace("+00:00", "Z"),
    }
    parsed_json = json.loads(response.content.decode("utf-8"))

    assert expected == parsed_json
    assert favorite.track == track
    assert favorite.actor.user == logged_in_api_client.user


def test_adding_favorites_calls_activity_record(
    factories, logged_in_api_client, activity_muted
):
    logged_in_api_client.user.create_actor()
    track = factories["music.Track"]()
    url = reverse("api:v1:favorites:tracks-list")
    response = logged_in_api_client.post(url, {"track": track.pk})

    favorite = TrackFavorite.objects.latest("id")
    expected = {
        "track": track.pk,
        "id": favorite.id,
        "creation_date": favorite.creation_date.isoformat().replace("+00:00", "Z"),
    }
    parsed_json = json.loads(response.content.decode("utf-8"))

    assert expected == parsed_json
    assert favorite.track == track
    assert favorite.actor.user == logged_in_api_client.user

    activity_muted.assert_called_once_with(favorite)


def test_user_can_remove_favorite_via_api(logged_in_api_client, factories):
    logged_in_api_client.user.create_actor()
    favorite = factories["favorites.TrackFavorite"](
        actor=logged_in_api_client.user.actor
    )
    url = reverse("api:v1:favorites:tracks-detail", kwargs={"pk": favorite.pk})
    response = logged_in_api_client.delete(url, {"track": favorite.track.pk})
    assert response.status_code == 204
    assert TrackFavorite.objects.count() == 0


@pytest.mark.parametrize("method", ["delete", "post"])
def test_user_can_remove_favorite_via_api_using_track_id(
    method, factories, logged_in_api_client
):
    logged_in_api_client.user.create_actor()
    favorite = factories["favorites.TrackFavorite"](
        actor=logged_in_api_client.user.actor
    )

    url = reverse("api:v1:favorites:tracks-remove")
    response = getattr(logged_in_api_client, method)(
        url, json.dumps({"track": favorite.track.pk}), content_type="application/json"
    )

    assert response.status_code == 204
    assert TrackFavorite.objects.count() == 0


@pytest.mark.parametrize("url,method", [("api:v1:favorites:tracks-list", "get")])
def test_url_require_auth(url, method, db, preferences, client):
    preferences["common__api_authentication_required"] = True
    url = reverse(url)
    response = getattr(client, method)(url)
    assert response.status_code == 401


def test_can_filter_tracks_by_favorites(factories, logged_in_api_client):
    logged_in_api_client.user.create_actor()
    favorite = factories["favorites.TrackFavorite"](
        actor=logged_in_api_client.user.actor
    )

    url = reverse("api:v1:tracks-list")
    response = logged_in_api_client.get(url, data={"favorites": True})

    parsed_json = json.loads(response.content.decode("utf-8"))
    assert parsed_json["count"] == 1
    assert parsed_json["results"][0]["id"] == favorite.track.id
