from django.contrib.auth import get_user_model
from django.db.models import F
from django.shortcuts import get_object_or_404
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import parsers, status
from rest_framework.generics import GenericAPIView, ListAPIView, UpdateAPIView
from rest_framework.response import Response

from apps.artiste.api.v1.serializers import (
    AlbumsSerializer,
    ArtisteSerializer,
    AudioMediaSerializer,
    BankAccountSerializer
)
from apps.artiste.models import Album, Artiste, AudioMedia,BankAccount
from apps.artiste.pagination import CustomPagination
from apps.lib.utils import GetObjectMixin
from profiles.serializers import FanProfileSerializer
from users.models import Fan
from rest_framework.views import APIView
import random
import stripe
from django.conf import settings
from rest_framework.permissions import AllowAny  # This allows any user to access the view
    

stripe.api_key = settings.STRIPE_SECRET_KEY

User = get_user_model()


# class ListAllArtisteAPIView(GetObjectMixin, GenericAPIView):
#     queryset = Artiste.objects.all()
#     serializer_class = ArtisteSerializer
#     pagination_class = CustomPagination

#     def get(self, request):
#         page = self.paginate_queryset(self.get_queryset())
#         if page is not None:
#             serializer = self.get_serializer(page, many=True)
#             return self.get_paginated_response(serializer.data)

#         serializer = self.get_serializer(self.get_queryset(), many=True)
#         return Response(serializer.data, status=status.HTTP_200_OK)

class ListAllArtisteAPIView(GetObjectMixin, GenericAPIView):
    queryset = Artiste.objects.all()
    serializer_class = ArtisteSerializer
    pagination_class = CustomPagination

    def get(self, request):
        queryset = self.get_queryset().exclude(profile_song__audio_file=None)  # exclude instances where audio_file is null
        # Shuffle the queryset
        shuffled_queryset = sorted(queryset, key=lambda x: random.random())
        page = self.paginate_queryset(shuffled_queryset)
        # page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(shuffled_queryset, many=True)
        # Shuffle the serialized data before returning it in the response
        shuffled_data = serializer.data.copy()
        random.shuffle(shuffled_data)
        return Response(shuffled_data, status=status.HTTP_200_OK)
        # return Response(serializer.data, status=status.HTTP_200_OK)

class ArtisteProfileAPIView(GetObjectMixin, GenericAPIView):
    queryset = Artiste.objects.all()
    serializer_class = ArtisteSerializer
    lookup_url_kwarg = 'artiste_uuid'

    def get(self, request, artiste_uuid):
        serializer = self.get_serializer(self.get_object())
        return Response(serializer.data, status=status.HTTP_200_OK)


class ArtisteAlbumsAPIView(GetObjectMixin, GenericAPIView):
    queryset = Album.objects.all()
    serializer_class = AlbumsSerializer
    pagination_class = CustomPagination
    lookup_url_kwarg = 'artiste_uuid'

    def get_queryset(self):
        artiste = get_object_or_404(Artiste, id=self.kwargs.get('artiste_uuid'))
        return Album.objects.filter(artiste=artiste)

    def get(self, request, artiste_uuid):
        page = self.paginate_queryset(self.get_queryset())
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(self.get_queryset(), many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class AlbumSongsAPIView(GetObjectMixin, GenericAPIView):
    queryset = AudioMedia.objects.annotate(current_score=F('score')).order_by('-current_score')
    serializer_class = AudioMediaSerializer
    lookup_url_kwarg = 'album_uuid'

    def get_queryset(self):
        album = get_object_or_404(Album, id=self.kwargs.get('album_uuid'))
        return AudioMedia.objects.filter(album=album).annotate(current_score=F('score')).order_by('-current_score')

    def get(self, request, album_uuid):
        page = self.paginate_queryset(self.get_queryset())
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(self.get_queryset(), many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class CreateAlbumAPIView(GetObjectMixin, GenericAPIView):
    serializer_class = AlbumsSerializer

    def post(self, request):
        artiste = self.get_object_by_model(Artiste, id=request.data.get('artiste'))
        data = {
            'artiste': artiste.id,
            'album_name': request.data.get('album_name'),
        }
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class DeleteAlbumAPIView(GetObjectMixin, GenericAPIView):
    queryset = Album.objects.all()
    serializer_class = AlbumsSerializer
    pagination_class = CustomPagination

    def delete(self, request, album_uuid):
        artiste = request.user.artiste
        try:
            album = Album.objects.get(id=self.kwargs.get('album_uuid'))
        except Album.DoesNotExist:
            return Response({"error": "Album does not exist"}, status=status.HTTP_404_NOT_FOUND)

        if album.artiste != artiste:
            return Response({'error': 'album does not belong to artiste'}, status=status.HTTP_400_BAD_REQUEST)

        update_list = []
        audio_media_queryset = AudioMedia.objects.filter(album=album)
        for audio in audio_media_queryset:
            audio.album = None
            update_list.append(audio)

        AudioMedia.objects.bulk_update(update_list, ["album"])
        album.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


class CreateSongAPIView(GetObjectMixin, GenericAPIView):
    serializer_class = AudioMediaSerializer
    parser_classes = [parsers.MultiPartParser, parsers.FileUploadParser]

    @swagger_auto_schema(
        operation_id='Upload Artiiste Song',
        operation_description='Upload Artiiste Song by providing audio_file and title',
        required=['artiste_uuid', 'audio_file'],
        manual_parameters=[
            openapi.Parameter('audio_file', openapi.IN_FORM, type=openapi.TYPE_FILE, description='Song to be uploaded'),
            openapi.Parameter('cover_image', openapi.IN_FORM, type=openapi.TYPE_FILE, description='Song Cover Image'),
            openapi.Parameter('artiste_uuid', openapi.IN_FORM, type=openapi.TYPE_STRING, description='Artiste UUID'),
            openapi.Parameter('album_uuid', openapi.IN_FORM, type=openapi.TYPE_STRING, description='Album  UUID'),
        ],
    )
    def post(self, request):
        artiste = self.get_object_by_model(Artiste, id=request.data.get('artiste_uuid'))
        album = None
        if request.data.get('album_uuid'):
            album = self.get_object_by_model(Album, id=request.data.get('album_uuid'))

        context = {
            'artiste': artiste,
            'album_name': album or None,
            'cover_image': request.data.get('cover_image', None),
            'audio_file': request.data.get('audio_file'),
        }
        serializer = self.get_serializer(data=request.data, context=context)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class DeleteSongAPIView(GetObjectMixin, GenericAPIView):
    queryset = AudioMedia.objects.annotate(current_score=F('score')).order_by('-current_score')
    serializer_class = AudioMediaSerializer
    pagination_class = CustomPagination

    def delete(self, request, audio_uuid):
        artiste = request.user.artiste
        try:
            audio_media = AudioMedia.objects.get(id=self.kwargs.get('audio_uuid'))
        except AudioMedia.DoesNotExist:
            return Response({"error": "AudioMedia does not exist"}, status=status.HTTP_404_NOT_FOUND)

        if audio_media.artiste != artiste:
            return Response({'error': 'song does not belong to artiste'}, status=status.HTTP_400_BAD_REQUEST)

        audio_media.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


class ArtisteSongsAPIView(ListAPIView):
    queryset = AudioMedia.objects.annotate(current_score=F('score')).order_by('-current_score')
    serializer_class = AudioMediaSerializer
    pagination_class = CustomPagination
    lookup_url_kwarg = 'artiste_uuid'

    def get_queryset(self):
        artiste = get_object_or_404(Artiste, id=self.kwargs.get('artiste_uuid'))
        return AudioMedia.objects.filter(artiste=artiste).annotate(current_score=F('score')).order_by('-current_score')


class SelectProfileSongAPIView(UpdateAPIView):
    model = Artiste
    serializer_class = ArtisteSerializer
    lookup_field = 'artiste_uuid'
    pagination_class = CustomPagination

    def get_queryset(self):
        return Artiste.objects.filter(id=self.kwargs.get('artiste_uuid'))

    def get_object(self):
        return get_object_or_404(Artiste, id=self.kwargs.get('artiste_uuid'))

    @swagger_auto_schema(
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['song_uuid'],
            properties={
                'song_uuid': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_UUID),
                'artiste_uuid': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_UUID),
            },
        ),
    )
    def patch(self, request):
        self.kwargs['artiste_uuid'] = request.data.get('artiste_uuid')
        self.kwargs['song_uuid'] = request.data.get('song_uuid')
        profile_song = get_object_or_404(AudioMedia, id=request.data.get('song_uuid'))

        serializer = self.get_serializer(self.get_object(), data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save(profile_song=profile_song)

        return Response(serializer.data)


class ArtisteFollowedAPIView(GetObjectMixin, GenericAPIView):
    queryset = Artiste.objects.all()
    serializer_class = ArtisteSerializer
    pagination_class = CustomPagination

    def get(self, request):
        # fan = self.get_object_by_model(Fan, id=request.user.id)
        follows = request.user.fan.get_followed()
        artiste_ids = [follow.artiste_id for follow in follows]
        artiste_queryset = Artiste.objects.filter(id__in=artiste_ids)

        page = self.paginate_queryset(artiste_queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(artiste_queryset, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class ArtisteFollowersAPIView(GetObjectMixin, GenericAPIView):
    queryset = Artiste.objects.all()
    serializer_class = FanProfileSerializer
    pagination_class = CustomPagination

    def get(self, request):
        artiste = self.get_object_by_model(Artiste, id=request.user.artiste.id)
        follows = artiste.get_followers()
        fan_ids = [follow.fan_id for follow in follows]
        fan_queryset = Fan.objects.filter(id__in=fan_ids)

        page = self.paginate_queryset(fan_queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(fan_queryset, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)



class AddBankAccountAPIView(APIView):
    def get(self, request):
        artiste = Artiste.objects.filter(id=request.GET.get('artiste_uuid')).first()
        bank_account = BankAccount.objects.filter(user_id=artiste.user.id).first()

        if not bank_account:
            return Response({"message": "No bank account found"}, status=404)
        else:
            serialized = BankAccountSerializer(bank_account)
        
        return Response(serialized.data, status=200)
    
    def post(self,request):
        artiste = Artiste.objects.filter(id=request.data.get('artiste_uuid')).first()
        account_holder_name = request.data.get('account_holder_name')
        bank_name = request.data.get('bank_name')
        account_number = request.data.get('account_number')
        routing_number = request.data.get('routing_number')
        account_type = request.data.get('account_type')
        currency = request.data.get('currency')
        
        check_account = BankAccount.objects.filter(user_id = artiste.user.id).first()
        if check_account:
            BankAccount.objects.filter(user_id = artiste.user.id).update(account_holder_name=account_holder_name,bank_name=bank_name,account_number=account_number,routing_number=routing_number,account_type=account_type,currency=currency)
        else:
            BankAccount.objects.create(user_id = artiste.user.id,account_holder_name=account_holder_name,bank_name=bank_name,account_number=account_number,routing_number=routing_number,account_type=account_type,currency=currency)
            
        artiste.is_bank_added = True
        artiste.save()
        return Response({'message': 'Success'}, status=200)
    
    
    
class AddFcmToken(APIView):
    def post(self,request):
        artist_id = request.data.get('artiste_uuid')
        if not artist_id:
            return Response({"message": "artist_id is required"}, status=404)
        artiste = Artiste.objects.filter(id=artist_id).first()
        if not artiste:
            return Response({"message": "No artiste found"}, status=404)
        
        fcm_token =  request.data.get('fcm_token')
        if not fcm_token:
            return Response({"message": "fcm_token is required"}, status=404)
        
        device_type =  request.data.get('device_type')
        if not device_type:
            return Response({"message": "device_type is required"}, status=404) 
        
        artiste.fcm_token = fcm_token
        artiste.device_type = device_type
        artiste.save()
        
        return Response({'message': 'Success'}, status=200)

        
class StripeAccountOnboardingCallback(APIView):
    authentication_classes = []
    permission_classes = [AllowAny]  # Allow anyone to access this endpoint

    def get(self, request):
        account_id = request.GET.get('account_id')
        
        if not account_id:
            return Response({"message": "Account ID is missing"}, status=400)
        
        try:
            # Retrieve the associated Stripe account
            account = stripe.Account.retrieve(account_id)
            # Check if the account is fully onboarded (you can adjust this condition as per your needs)
            if account.capabilities.transfers == 'active':
                # Update your model to reflect the successful setup
                artiste = Artiste.objects.filter(stripe_account_id=account.id).first()
                if artiste:
                    artiste.stripe_account_verified = True  # You may need to create this field
                    artiste.save()
                
                return Response({
                    'message': 'Stripe account setup completed successfully!',
                    'stripe_account_id': account.id
                }, status=200)
            
            else:
                return Response({
                    'message': 'Stripe account setup not completed',
                    'account_status': account.capabilities.transfers
                }, status=400)
        
        except stripe.error.StripeError as e:
            return Response({
                'message': 'Stripe error occurred during callback',
                'error': str(e)
            }, status=500)
        
        except Exception as e:
            return Response({
                'message': 'Error processing the Stripe callback',
                'error': str(e)
            }, status=500)
        
class ConnectStripe(APIView):
    def get(self,request):
        artist_id = request.GET.get('artiste_uuid')
        if not artist_id:
            return Response({"message": "artist_id is required"}, status=404)

        artiste = Artiste.objects.filter(id=artist_id).first()
        if not artiste:
            return Response({"message": "No artiste found"}, status=404)
        return Response({
                'message': 'Fetched successfully',
                'account_id': artiste.stripe_account_id,
            })
        
    def post(self, request):
        artist_id = request.data.get('artiste_uuid')
        if not artist_id:
            return Response({"message": "artist_id is required"}, status=404)

        artiste = Artiste.objects.filter(id=artist_id).first()
        if not artiste:
            return Response({"message": "No artiste found"}, status=404)
                            
        # if artiste.stripe_account_id:
        #     return Response({'message': 'Stripe ID already created'}, status=200)

        try:
            # Create Stripe account
            if not artiste.stripe_account_id:
                account = stripe.Account.create(
                    type="standard",
                    country="US",
                    email=artiste.user.email,
                )
                
                artiste.stripe_account_id = account.id
                artiste.save()
                account_id = account.id
            else:
                account_id =  artiste.stripe_account_id
                
            return_url = f"https://saigon-music-26825-staging.azurewebsites.net/artiste/stripe-account-setup-callback?account_id={account_id}"

            # Create an account link
            account_link = stripe.AccountLink.create(
                account=account_id,
                refresh_url="https://saigon-music-26825-staging.azurewebsites.net/stripe-account-setup",
                return_url=return_url,
                type="account_onboarding",
            )

            return Response({
                'message': 'Stripe ID created successfully',
                'account_link_url': account_link.url,
                'return_url':return_url,
            }, status=200)

        except Exception as e:
            print(f"Error creating Stripe account: {str(e)}")
            return Response({
                "message": "Error creating Stripe account",
                "error": str(e)
            }, status=500)


    
        