from django.utils.timezone import datetime, timedelta
from django.utils import timezone
import json
import requests
import lxml.html

from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
from django.db.models.functions import ExtractWeek, ExtractYear
from django.urls import reverse
from django.utils.timesince import timesince


User = get_user_model()



class Settings(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)
    key = models.CharField(max_length=1024, unique=True)
    value = models.JSONField(default=dict, editable=False)


class Item(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)


    title = models.CharField(max_length=1024)
    url = models.CharField(max_length=1024, unique=True)
    description = models.TextField(default="", blank=True, editable=False)
    published = models.DateTimeField(default=None, null=True, blank=True)
    announced = models.DateTimeField(null=True, default=None, blank=True, editable=False)
    data = models.JSONField(default=dict, editable=False)
    user = models.ForeignKey(User, null=True, related_name='items', on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        #if self.url and not self.data.get("url") == self.url:
        if self.url:
            self.update_data()
        super().save(*args, **kwargs)

    def __str__(self):
        return '%s (%s)' % (self.title, self.url)

    def public_comments(self):
        return self.comments.exclude(published=None)

    def public_comments_json(self):
        comments = []
        for comment in self.public_comments():
            comments.append({
                "name": comment.name,
                "date": comment.date,
                "text": comment.text,
            })
        return json.dumps(comments)

    @classmethod
    def all_public(cls, now=None):
        if now is None:
            now = timezone.make_aware(datetime.now(), timezone.get_default_timezone())
        qs = cls.objects.exclude(published=None).filter(published__lte=now).order_by('-published')
        archive = qs.annotate(year=ExtractYear('published')).annotate(week=ExtractWeek('published'))
        return archive

    @classmethod
    def public(cls, now=None):
        if now is None:
            now = timezone.make_aware(datetime.now(), timezone.get_default_timezone())
        qs = cls.all_public(now)
        cal = now.date().isocalendar()
        monday = now.date() - timedelta(days=now.date().isocalendar().weekday - 1)
        monday = timezone.datetime(monday.year, monday.month, monday.day, tzinfo=now.tzinfo)
        first_post = qs.filter(published__gt=monday).first()
        if first_post and first_post.published < now:
            week = qs.filter(published__gt=monday)
        elif not first_post:
            while qs.exists() and not first_post:
                monday = monday - timedelta(days=7)
                first_post = qs.filter(published__gt=monday).first()
            week = qs.filter(published__gt=monday)
        else:
            last_monday = monday - timedelta(days=7)
            week = qs.filter(published__gt=last_monday)
        archive = qs.exclude(id__in=week)
        return week, archive

    def get_week(self):
        return int(self.published.strftime('%W'))

    def get_year(self):
        return int(self.published.strftime('%Y'))

    def get_monday(self):
        d = '%s-W%s' % (self.get_year(), self.get_week())
        return datetime.strptime(d + '-1', "%Y-W%W-%w").strftime('%Y-%m-%d')

    def get_absolute_url(self):
        return reverse('item', kwargs={'id': self.id})

    def full_url(self):
        return settings.URL + self.get_absolute_url()

    def update_data(self):
        self.data.update(self.parse_url())

    def parse_url(self):
        content = requests.get(self.url).text
        doc = lxml.html.fromstring(content)
        data = {}
        for meta in doc.cssselect('meta'):
            key = meta.attrib.get('name')
            if not key:
                key = meta.attrib.get('property')
            value = meta.attrib.get('content')
            if key and value:
                if key in ('viewport', ):
                    continue
                key = key.replace('og:', '')
                data[key] = value
        data["url"] = self.url
        if "m/documents" in self.url:
            data["type"] = "document"
            data["thumbnail"] = data["thumbnail"].replace('/512p', '/1024p')
        return data


class Comment(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    item = models.ForeignKey(Item, related_name='comments', on_delete=models.CASCADE)
    text = models.TextField(default="")

    name = models.CharField(max_length=1024, blank=True)
    email = models.CharField(max_length=1024, blank=True)

    user = models.ForeignKey(User, null=True, related_name='comments', on_delete=models.CASCADE, blank=True)
    session_key = models.CharField(max_length=60, null=True, default=None, blank=True, editable=False)

    data = models.JSONField(default=dict, editable=False)
    published = models.DateTimeField(null=True, default=None, blank=True)

    class Meta:
        permissions = [
            ("can_post_comment", "Can post comments without moderation")
        ]

    @property
    def is_published(self):
        return bool(self.published)

    def __str__(self):
        return '%s: %s' % (self.item, self.user)

    def save(self, *args, **kwargs):
        if self.user:
            self.name = self.user.username
            self.email = self.user.email
        super().save(*args, **kwargs)

    @property
    def date(self):
        now = timezone.now()
        difference = now - self.created
        if difference <= timedelta(minutes=1):
            return "just now"
        return '%(time)s ago' % {'time': timesince(self.created).split(', ')[0]}
        return self.created.strftime('%B %d, %Y at %H:%M')
        return self.created.strftime('%Y-%m-%d %H:%M')

    def json(self):
        data = {}
        if not self.user:
            data['name'] = '%s (guest)' % self.name
        else:
            data['name'] = self.name
        data['date'] = self.date
        data['text'] = self.text
        data['id'] = self.id
        data['published'] = self.is_published
        return data


class Week(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)
    monday = models.DateField(unique=True)
    title = models.CharField(max_length=2048, blank=True, default="")
    byline = models.CharField(max_length=2048, blank=True, default="")
    published = models.DateTimeField(null=True, default=None, blank=True, editable=False)

    def __str__(self):
        return "%s (%s)" % (self.title, self.monday)