from django.db import models
from django.contrib.auth.models import User
from .track import Track
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils import timezone
from datetime import datetime, timedelta, UTC
from ..spotify import spt
import os
from dotenv import load_dotenv

load_dotenv()

NOMINATIONS_PER_DAY = 10
MAX_QUOTA = 22

class Background(models.Model):
    def __str__(self):
        return self.name
    name = models.CharField(max_length=128)
    image = models.ImageField(upload_to="wallpapers/", null=True, blank=True)
    repeat = models.BooleanField(default=False)
    cover = models.BooleanField(default=False)
    color = models.CharField(max_length=32, blank=True)

class Profile(models.Model):
    def __str__(self):
        return str(self.user)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    background = models.ForeignKey(Background, null=True, on_delete=models.SET_NULL)
    last_voted = models.ForeignKey(Track, null=True, on_delete=models.SET_NULL)

    quota = models.FloatField(default=10.0)
    quota_last_updated = models.DateTimeField(default=timezone.now, null=False)

    spt_access_token = models.CharField(max_length=256, default="", blank=True, null=True)
    spt_refresh_token = models.CharField(max_length=256, default="", blank=True, null=True)
    spt_expires = models.DateTimeField(default=None, null=True)

    @property
    def quota_display(self):
       return int(self.quota)

    def update_quota(self):
        elapsed = timezone.now() - self.quota_last_updated
        if elapsed.total_seconds() > 300:
            noms_per_second = NOMINATIONS_PER_DAY/(60*60*24)
            self.quota += noms_per_second * elapsed.total_seconds()
            self.quota = min(self.quota, MAX_QUOTA)
            print(f"{self.user.username}: Er zijn {elapsed.total_seconds()}s voorbij, je nieuwe quota is {self.quota}")
            self.quota_last_updated = timezone.now()

    @property
    def can_nominate(self):
        """Is this user allowed to nominate at this point in time?"""
        end_date = os.getenv('DATE_NOM_END')
        if self.user.is_superuser:
            return (True, None)
        if end_date:
            end_date = datetime.fromisoformat(end_date)
            if end_date <= datetime.now(tz=UTC):
                return (False, "over")
        if self.quota < 1:
            return (False, "quota")
        return (True, None)

    @property
    def can_vote(self):
        """Is this user allowed to vote at this point in time?"""
        end_date = os.getenv('DATE_VOTE_END')
        if self.user.is_superuser or not end_date:
            return True
        end_date = datetime.fromisoformat(end_date)
        if end_date <= datetime.now(tz=UTC):
            return False
        return True

    @property
    def vote_end(self):
        return os.getenv('DATE_VOTE_END')

    @property
    def nominate_end(self):
        return os.getenv('DATE_NOM_END')

    def init_spt(self, code):
        """Initial setting of spotify tokens from user accept code"""
        data = spt.get_token_json(
            grant_type='authorization_code',
            code=code
        )
        self.save_spt(data)

    def refresh_spt(self):
        """Refreshes expired access token using stored refresh token"""
        if self.spt_refresh_token:
            data = spt.get_token_json(
                grant_type='refresh_token',
                refresh_token=self.spt_refresh_token
            )
            self.save_spt(data)

    def save_spt(self, data):
        """Saves tokens from json response"""
        access = data.get('access_token', None)
        refresh = data.get('refresh_token', self.spt_refresh_token)
        expires = data.get('expires_in', 3600)
        self.spt_access_token = access
        self.spt_refresh_token = refresh
        self.spt_expires = timezone.now() + timedelta(seconds=expires - 300)
        self.save()

    def unlink_spt(self):
        self.spt_access_token = None
        self.spt_refresh_token = None
        self.spt_expires = None

    @property
    def can_spt(self):
        return (
            self.spt_access_token and
            self.spt_expires and
            (timezone.now() < self.spt_expires)
        )

    def get_or_update_spt(self):
        if self.spt_refresh_token:
            if not self.can_spt:
                self.refresh_spt()
            return self.spt_access_token
        return None

    def save(self, *args, **kwargs):
        self.update_quota()
        super().save(*args, **kwargs)

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    Profile.objects.get_or_create(user=instance)
    instance.profile.save()
