import io

from django.contrib.auth import get_user_model
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.db import IntegrityError
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from pydub import AudioSegment
from rest_framework import permissions, status
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from apps.actions.api.v1.serializers import FollowArtisteSerializer, LikeMediaSerializer, PrivacyPolicySerializer
from apps.actions.constants import ACTION_DISLIKE, ACTION_LIKE
from apps.actions.models import Follow, MediaLikes, PrivacyPolicy
from apps.artiste.api.v1.serializers import AudioMediaSerializer
from apps.artiste.constants import REQUESTED_VERIFICATION
from apps.artiste.models import Artiste, AudioMedia
from apps.lib.utils import GetObjectMixin, calculate_audio_media_score
from users.constants import ACCOUNT_TYPE_ARTISTE, ACCOUNT_TYPE_FAN
from users.models import Fan

User = get_user_model()


def get_calculated_data(audio_media, message):
    data = {
        "likes_count": audio_media.get_likes_count(),
        "dislikes_count": audio_media.get_dislikes_count(),
    }
    calculate_audio_media_score(audio_media)
    return Response({"message": message, "data": data}, status=status.HTTP_200_OK)


class LikeMediaAPIView(GetObjectMixin, GenericAPIView):
    queryset = MediaLikes.objects.all()
    serializer_class = LikeMediaSerializer
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, media_uuid):
        try:
            audio_media = self.get_object_by_model(AudioMedia, media_uuid)
        except AudioMedia.DoesNotExist:

            return Response({"message": "No AudioMedia found with request UUID"}, status=status.HTTP_404_NOT_FOUND)

        fan = self.get_related_object_by_model(User, request.user.id, 'fan')
        created = False

        try:
            media_like, created = MediaLikes.objects.get_or_create(fan=fan, media=audio_media, action_type=ACTION_LIKE)
        except IntegrityError:
            MediaLikes.objects.filter(fan=fan, media=audio_media, action_type=ACTION_DISLIKE).delete()
            MediaLikes.objects.create(fan=fan, media=audio_media, action_type=ACTION_LIKE)
            return get_calculated_data(audio_media, "Music liked successfully")
        if created:
            return get_calculated_data(audio_media, "Music liked successfully")
        return get_calculated_data(audio_media, "You have already like this music!")


class DislikeMediaAPIView(GetObjectMixin, GenericAPIView):
    queryset = MediaLikes.objects.all()
    serializer_class = LikeMediaSerializer
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, media_uuid):
        try:
            audio_media = self.get_object_by_model(AudioMedia, media_uuid)
        except AudioMedia.DoesNotExist:
            return Response({"message": "No AudioMedia found with request UUID"}, status=status.HTTP_404_NOT_FOUND)
        fan = self.get_related_object_by_model(User, request.user.id, 'fan')

        try:
            media_like, created = MediaLikes.objects.get_or_create(
                fan=fan, media=audio_media, action_type=ACTION_DISLIKE
            )
        except IntegrityError:
            MediaLikes.objects.filter(fan=fan, media=audio_media, action_type=ACTION_LIKE).delete()
            MediaLikes.objects.create(fan=fan, media=audio_media, action_type=ACTION_DISLIKE)
            return get_calculated_data(audio_media, "Music disliked successfully")
        if created:
            return get_calculated_data(audio_media, "Music disliked successfully")
        return get_calculated_data(audio_media, "You have already like this music!")


class FollowUnfollowArtisteAPIView(GetObjectMixin, GenericAPIView):
    queryset = Follow.objects.all()
    serializer_class = FollowArtisteSerializer
    permission_classes = [permissions.IsAuthenticated]
    model = Follow

    def post(self, request, artiste_uuid, *args, **kwargs):
        try:
            artiste = self.get_object_by_model(Artiste, artiste_uuid)
        except Artiste.DoesNotExist:
            return Response({"message": "No Artiste found with request UUID"}, status=status.HTTP_404_NOT_FOUND)
        fan = self.get_related_object_by_model(User, request.user.id, 'fan')

        # check if the Follow object already exists
        follow, created = Follow.objects.get_or_create(artiste=artiste, fan=fan)

        if not created:
            # Follow object already exists, so delete it
            follow.delete()
            status_code = status.HTTP_200_OK
            message = "Unfollowed artiste successfully"
        else:
            status_code = status.HTTP_201_CREATED
            message = "Followed artiste successfully"

        # return a success response
        return Response({'message': message}, status=status_code)


class AcceptTermsAndConditionsAPIView(GetObjectMixin, APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        user = request.user
        user_type = user.account_type

        if user_type == ACCOUNT_TYPE_FAN:
            model_class = Fan
        elif user_type == ACCOUNT_TYPE_ARTISTE:
            model_class = Artiste
        else:
            return Response({"error": "Invalid Account type"}, status=status.HTTP_400_BAD_REQUEST)

        user_instance = model_class.objects.get(user=user)
        user_instance.is_accepted_terms = not user_instance.is_accepted_terms
        user_instance.save(update_fields=['is_accepted_terms'])

        if user_instance.is_accepted_terms:
            message = 'Terms and conditions accepted successfully'
        else:
            message = 'Terms and conditions unaccepted successfully'

        return Response({'message': message}, status=status.HTTP_200_OK)


class PrivacyPolicyAPIView(ModelViewSet):
    permission_classes = [permissions.AllowAny]
    serializer_class = PrivacyPolicySerializer
    queryset = PrivacyPolicy.objects.all()


class AcceptPrivacyPolicyAPIView(GetObjectMixin, APIView):
    # permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        user = request.user
        user_type = user.account_type

        if user_type == ACCOUNT_TYPE_FAN:
            model_class = Fan
        elif user_type == ACCOUNT_TYPE_ARTISTE:
            model_class = Artiste
        else:
            return Response({"error": "Invalid Account type"}, status=status.HTTP_400_BAD_REQUEST)

        user_instance = model_class.objects.get(user=user)
        user_instance.is_accepted_privacy = not user_instance.is_accepted_privacy
        user_instance.save(update_fields=['is_accepted_privacy'])

        if user_instance.is_accepted_privacy:
            message = 'Privacy Policy accepted successfully'
        else:
            message = 'Privacy Policy unaccepted successfully'

        return Response({'message': message}, status=status.HTTP_200_OK)


class RequestVerificationAPIView(GetObjectMixin, APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, *args, **kwargs):
        user_type = request.user.account_type

        if user_type != ACCOUNT_TYPE_ARTISTE:
            return Response({"error": "Invalid Account type"}, status=status.HTTP_400_BAD_REQUEST)

        artiste = self.get_related_object_by_model(User, request.user.id, 'artiste')

        if artiste.verification_status == REQUESTED_VERIFICATION:
            response = "Verification request already sent"
        else:
            artiste.verification_status = REQUESTED_VERIFICATION
            artiste.save()
            response = "Verification request sent"

        return Response({"message": response}, status=status.HTTP_200_OK)


class TrimSongAPIView(GetObjectMixin, APIView):
    serializer_class = AudioMediaSerializer

    @swagger_auto_schema(
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['audio_uuid'],
            properties={
                'trim_start': openapi.Schema(type=openapi.TYPE_STRING),
                'trim_end': openapi.Schema(type=openapi.TYPE_STRING),
                'audio_uuid': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_UUID),
            },
        ),
    )
    def post(self, request):
        original_audio = self.get_object_by_model(AudioMedia, request.data.get('audio_uuid'))

        if original_audio.artiste != request.user.artiste:
            return Response({"error": "Song Doesn\'t belong to artiste"}, status=status.HTTP_400_BAD_REQUEST)

        trim_start = float(request.data.get('trim_start')) * 1000
        trim_end = float(request.data.get('trim_end')) * 1000

        file_object = default_storage.open(original_audio.audio_file.name, mode='rb')

        # Open the original audio file with Pydub
        audio = AudioSegment.from_file(file_object, format=original_audio.audio_file.name.split('.')[-1])

        # Trim the audio to the first 30 seconds
        trimmed_audio = audio[trim_start:trim_end]

        # Create a new AudioMedia object with the same attributes as the original
        # new_audio = AudioMedia(
        #     album=original_audio.album,
        #     artiste=original_audio.artiste,
        #     cover_image=original_audio.cover_image,
        #     duration=str(trimmed_audio.duration_seconds),
        #     score=original_audio.score,
        #     title=original_audio.title,
        # )

        # Save the trimmed audio to a new file
        trimmed_file = io.BytesIO()
        trimmed_audio.export(trimmed_file, format=original_audio.audio_file.name.split('.')[-1])
        trimmed_file.seek(0)

        # Save the file to AWS S3
        filename = f"{original_audio.title[:10]}-{original_audio.id}.{original_audio.audio_file.name.split('.')[-1]}"
        file_path = default_storage.save(filename, ContentFile(trimmed_file.read()))

        original_audio.audio_file = file_path
        original_audio.duration = str(trimmed_audio.duration_seconds)
        original_audio.save(update_fields=['audio_file', 'duration'])

        # Set the new AudioMedia object's audio file to the new file
        # new_audio.audio_file = file_path

        # Save the new AudioMedia object to the database
        # new_audio.save()

        # Set the new Audio as Profile song
        # new_audio.save()
        request.user.artiste.profile_song = original_audio
        request.user.artiste.save()

        return Response({"message": "Trimmed successfully"}, status=status.HTTP_200_OK)
