from mongoengine import *
import datetime
import urllib
import simplejson as json
import urllib.request as request
from time import mktime
from django.contrib.auth.models import User
from reader.learn import predict_articles


class Source(Document):
    title = StringField(required=True)
    alias = StringField(required=True, unique=True)
    description = StringField()

    def __str__(self):
        return self.title

    def update_articles(self):
        pass

    meta = {'allow_inheritance': True}


class Reader(Document):
    user_id = IntField(required=True, unique=True)
    brain = BinaryField()
    subscriptions = ListField(ReferenceField(Source,
                                             reverse_delete_rule=NULLIFY))
    preferred_article_view = StringField(choices=('frame', 'article'),
                                         default='frame')
    reading_list = ListField(DictField())

    def subscribe(self, source):
        self.update(add_to_set__subscriptions=[source])

    def unsubscribe(self, source):
        self.update(pull_all__subscriptions=[source])

    def is_subscribed(self, source):
        return source in self.subscriptions

    def extend_reading_list(self):
        if len(self.reading_list) > 10:
            return

        if len(ReadRecord.objects(reader=self)) == 0:
            self.update(add_to_set__reading_list=[{"score": 0, "article_id": x.id} for x in Article.objects[:5]])
            return

        predicted = predict_articles(self, Article.objects.filter(
            source__in=self.subscriptions,
            id__nin=[x.article.id for x in ReadRecord.objects(reader=self)] + [x['article_id'] for x in self.reading_list]))
        self.update(add_to_set__reading_list=[{"score": x[1], "article_id": x[0].id} for x in predicted])

    @staticmethod
    def reader_for(user):
        try:
            return Reader.objects.get(user_id=user.id)
        except Reader.DoesNotExist:
            reader = Reader(user_id=user.id)
            reader.save()
            try:
                hackernews = Source.objects.get(alias="hackernews")
            except Source.DoesNotExist:
                hackernews = HackerNewsSource(alias="hackernews", title="Hacker News")
                hackernews.save()
            reader.subscribe(hackernews)
            reader.extend_reading_list()
            return reader


class Article(Document):
    title = StringField(required=True)
    content_text = StringField(required=True)
    content_html = StringField(required=True)
    url = StringField(required=True, unique=True)
    date_published = DateTimeField(required=True,
                                   default=datetime.datetime.now)
    is_framing_allowed = BooleanField(default=True, required=True)
    source = ReferenceField(Source, required=True, reverse_delete_rule=CASCADE)

    meta = {'allow_inheritance': True}

    def update_content_by_url(self):
        from boilerpipe.extract import Extractor
        extractor = Extractor(extractor='ArticleExtractor', url=self.url)
        self.content_html = extractor.getHTML()
        self.content_text = extractor.getText()

    def check_framing_allowed(self):
        from django.conf import settings
        request = urllib.request.Request(self.url)
        request.add_header("Referer", settings.BASE_URL)
        try:
            opener = urllib.request.urlopen(request)
        except Exception:
            self.is_framing_allowed = False
            return
        framing_allowed = not ('x-frame-options' in opener.headers)
        self.is_framing_allowed = framing_allowed

    def __str__(self):
        return (self.title + " [" + self.url + "]")

    @staticmethod
    def get_or_new(**kwargs):
        try:
            return Article.objects.get(**kwargs), False