from django.db import models
from django.contrib.auth.models import User
from django.db.models import Count, Q
from django.db.models.signals import post_save
from django.dispatch import receiver
from allauth.socialaccount.models import SocialToken
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
from django.conf import settings


class Untube(models.Model):
    page_likes = models.IntegerField(default=0)


# extension of the built in User model made by Django
class Profile(models.Model):
    untube_user = models.OneToOneField(User, on_delete=models.CASCADE)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    # settings
    robohash_set = models.IntegerField(default=3)  # determines profile picture from https://robohash.org/
    user_summary = models.CharField(max_length=300, default="I think my arm is on backward.")
    user_location = models.CharField(max_length=100, default="Hell, Earth")

    ### GLOBAL preferences ###
    # site preferences
    open_search_new_tab = models.BooleanField(default=True)  # open search page in new tab by default
    enable_gradient_bg = models.BooleanField(default=False)

    # playlist preferences (this will apply to all playlists)
    hide_unavailable_videos = models.BooleanField(default=True)
    confirm_before_deleting = models.BooleanField(default=True)
    ###########################

    # manage user
    show_import_page = models.BooleanField(default=True)  # shows the user tips for a week
    yt_channel_id = models.TextField(default='')
    import_in_progress = models.BooleanField(
        default=False)  # if True, will not let the user access main site until they import their YT playlists
    imported_yt_playlists = models.BooleanField(default=False)  # True if user imported all their YT playlists

    # google api token details
    access_token = models.TextField(default="")
    refresh_token = models.TextField(default="")
    expires_at = models.DateTimeField(blank=True, null=True)

    # import playlist page
    manage_playlists_import_textarea = models.TextField(default="")

    # create playlist page
    create_playlist_name = models.CharField(max_length=50, default="")
    create_playlist_desc = models.CharField(max_length=50, default="")
    create_playlist_type = models.CharField(max_length=50, default="")
    create_playlist_add_vids_from_collection = models.CharField(max_length=50, default="")
    create_playlist_add_vids_from_links = models.CharField(max_length=50, default="")

    def __str__(self):
        return f"{self.untube_user.username} ({self.untube_user.email})"

    def get_credentials(self):
        """
        Returns Google OAuth credentials object by using user's OAuth token
        """
        # if the profile model does not hold the tokens, retrieve them from user's SocialToken entry and save them into profile
        if self.access_token.strip() == "" or self.refresh_token.strip() == "":
            user_social_token = SocialToken.objects.get(account__user=self.untube_user)
            self.access_token = user_social_token.token
            self.refresh_token = user_social_token.token_secret
            self.expires_at = user_social_token.expires_at
            self.save(update_fields=['access_token', 'refresh_token', 'expires_at'])

        # app = SocialApp.objects.get(provider='google')
        credentials = Credentials(
            token=self.access_token,
            refresh_token=self.refresh_token,
            token_uri="https://oauth2.googleapis.com/token",
            client_id=settings.GOOGLE_OAUTH_CLIENT_ID,  # app.client_id,
            client_secret=settings.GOOGLE_OAUTH_CLIENT_SECRET,  # app.secret,
            scopes=['https://www.googleapis.com/auth/youtube']
        )

        if not credentials.valid:
            credentials.refresh(Request())
            self.access_token = credentials.token
            self.refresh_token = credentials.refresh_token
            self.save(update_fields=['access_token', 'refresh_token'])

        return credentials

    def get_channels_list(self):
        channels_list = []
        videos = self.untube_user.videos.filter(Q(is_unavailable_on_yt=False) & Q(was_deleted_on_yt=False))

        queryset = videos.values(
            'channel_name').annotate(channel_videos_count=Count('video_id')).order_by('-channel_videos_count')

        for entry in queryset:
            channels_list.append(entry['channel_name'])

        return channels_list

    def get_playlists_list(self):
        return self.untube_user.playlists.all().filter(is_in_db=True)


# as soon as one User object is created, create an associated profile object
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(untube_user=instance)


# whenever User.save() happens, Profile.save() also happens
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()