from app import db
from enum import Enum
from sqlalchemy.orm import backref
from datetime import datetime, timedelta
from collections import Counter


class Poll(db.Model):
    """Default class for polls"""

    __tablename__ = 'poll'

    # Names of templates
    template = 'defaultpoll.html'

    # Unique ID
    id = db.Column(db.Integer, primary_key=True)

    # Type
    type = db.Column(db.String(20))

    # Author
    author_id = db.Column(db.Integer, db.ForeignKey('member.id'))
    author = db.relationship('Member', backref=backref('polls'),
        foreign_keys=author_id)

    # Title/question
    title = db.Column(db.UnicodeText)

    # Start datetime
    start = db.Column(db.DateTime, default=datetime.now())

    # End datetime
    end = db.Column(db.DateTime)

    # Choices
    # We want a size-variable list of strings, or a dictionnary with
    # key/values, depending on the poll type.
    # As the data is likely to be adapted to the poll type, the PickleType
    # seems to be appropriate. Same applies for PollAnswer.
    choices = db.Column(db.PickleType)

    # Other fields populated automatically through relations:
    #  <answers>   The list of answers (of type PollAnswer)

    __mapper_args__ = {
        'polymorphic_identity': __tablename__,
        'polymorphic_on':type
    }

    def __init__(self, author, title, choices, start=datetime.now(), end=datetime.now()):
        self.author = author
        self.title = title
        self.choices = choices
        self.start = start
        self.end = end

    def delete(self):
        """Deletes a poll and its answers"""
        for a in self.answers:
            db.session.delete(a)
        db.session.commit()
        db.session.delete(self)

    # Common properties and methods
    @property
    def started(self):
        """Returns whether the poll is open"""
        return self.start <= datetime.now()

    @property
    def ended(self):
        """Returns whether the poll is closed"""
        return self.end < datetime.now()

    def has_voted(self, user):
        """Returns wheter the user has voted"""
        # TODO: use ORM for this dirty request
        return user in [a.author for a in self.answers]

    def can_vote(self, user):
        """Returns true if the current user can vote.
        More conditions may be added in the future"""
        return user.is_authenticated

    # Poll-specific methods. Must be overrided per-poll definition
    def vote(self, user, data):
        """Return a PollAnswer object from specified user and data"""
        return None

    @property
    def results(self):
        """Returns an easy-to-use object with answers of the poll."""
        return None


class PollAnswer(db.Model):
    """An answer to a poll"""

    __tablename__ = 'pollanswer'

    # Unique ID
    id = db.Column(db.Integer, primary_key=True)

    # Poll
    poll_id = db.Column(db.Integer, db.ForeignKey('poll.id'), index=True)
    poll = db.relationship('Poll', backref=backref('answers'),
        foreign_keys=poll_id)

    # Author. Must be Member
    author_id = db.Column(db.Integer, db.ForeignKey('member.id'))
    author = db.relationship('Member', foreign_keys=author_id)

    # Choice(s)
    answer = db.Column(db.PickleType)

    def __init__(self, poll, user, answer):
        self.poll = poll
        self.author = user
        self.answer = answer
