import random
from datetime import timedelta
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from django.db.models.signals import post_save
from django.dispatch import receiver
from constance import config as site_config
from django_lcore.core import LcoreUserProfileMethods, setup_sync_hooks, VPN_AUTH_STORAGE

from ccvpn.common import get_trial_period_duration
from payments.models import Subscription

prng = random.SystemRandom()


def random_gift_code():
    charset = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ"
    return ''.join([prng.choice(charset) for n in range(10)])


class VPNUser(models.Model, LcoreUserProfileMethods):
    class Meta:
        verbose_name = _("VPN User")
        verbose_name_plural = _("VPN Users")

    user = models.OneToOneField(User, on_delete=models.CASCADE)
    notes = models.TextField(blank=True)

    expiration = models.DateTimeField(blank=True, null=True)
    last_expiry_notice = models.DateTimeField(blank=True, null=True)
    last_vpn_auth_fail_notice = models.DateTimeField(blank=True, null=True)
    notify_expiration = models.BooleanField(default=True)
    notify_vpn_auth_fail = models.BooleanField(default=True)

    trial_periods_given = models.IntegerField(default=0)

    last_vpn_auth = models.DateTimeField(blank=True, null=True)
    last_core_sync = models.DateTimeField(blank=True, null=True)

    referrer = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL,
                                 related_name='referrals')
    referrer_used = models.BooleanField(default=False)
    campaign = models.CharField(blank=True, null=True, max_length=64)

    def clear_fields(self):
        self.expiration = None
        self.last_expiry_notice = None
        self.last_vpn_auth = None
        self.last_core_sync = None
        self.referrer = None
        self.referrer_used = False
        self.campaign = None

    def give_trial_period(self):
        self.add_paid_time(get_trial_period_duration())
        self.trial_periods_given += 1

    @property
    def can_have_trial(self):
        if self.trial_periods_given >= site_config.TRIAL_PERIOD_MAX:
            return False
        if self.user.payment_set.filter(status='confirmed').count() > 0:
            return False
        return True

    @property
    def remaining_trial_periods(self):
        return site_config.TRIAL_PERIOD_MAX - self.trial_periods_given

    def on_payment_confirmed(self, payment):
        if self.referrer and not self.referrer_used:
            self.referrer.vpnuser.add_paid_time(timedelta(days=14))
            self.referrer.vpnuser.save()
            self.referrer_used = True

    def get_subscription(self, include_unconfirmed=False):
        """ Tries to get the active (and most recent) Subscription """
        s = Subscription.objects.filter(user=self.user, status='active') \
                                .order_by('-id') \
                                .first()
        if s is not None or include_unconfirmed is False:
            return s
        s = Subscription.objects.filter(user=self.user, status='unconfirmed') \
                                .order_by('-id') \
                                .first()
        return s

    def lcore_sync(self):
        if VPN_AUTH_STORAGE == 'inst':
            return
        from lambdainst.tasks import push_user
        push_user.delay(user_id=self.user.id)

    def __str__(self):
        return self.user.username

setup_sync_hooks(User, VPNUser)

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


class GiftCode(models.Model):
    class Meta:
        verbose_name = _("Gift Code")
        verbose_name_plural = _("Gift Codes")

    code = models.CharField(max_length=32, default=random_gift_code)
    time = models.DurationField(default=timedelta(days=30))
    created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    created_by = models.ForeignKey(User, related_name='created_giftcode_set',
                                   on_delete=models.CASCADE, null=True, blank=True)
    single_use = models.BooleanField(default=True)
    free_only = models.BooleanField(default=True)
    available = models.BooleanField(default=True)
    comment = models.TextField(blank=True)
    users = models.ManyToManyField(User, through='GiftCodeUser')

    def use_on(self, user):
        if not self.available:
            return False
        if self.free_only and user.vpnuser.is_paid:
            return False

        link = GiftCodeUser(user=user, code=self)
        link.save()

        user.vpnuser.add_paid_time(self.time)
        user.vpnuser.save()

        if self.single_use:
            self.available = False

        self.save()

        return True

    @property
    def comment_head(self):
        head = self.comment.split('\n', 1)[0]
        if len(head) > 80:
            head = head[:80] + "..."
        return head

    def __str__(self):
        return self.code


class GiftCodeUser(models.Model):
    class Meta:
        verbose_name = _("Gift Code User")
        verbose_name_plural = _("Gift Code Users")

    user = models.ForeignKey(User, on_delete=models.CASCADE)
    code = models.ForeignKey(GiftCode, on_delete=models.CASCADE)
    date = models.DateTimeField(auto_now_add=True, null=True, blank=True)

    def __str__(self):
        return "%s (%s)" % (self.user.username, self.code.code)

