from threading import *
from Models import *
from Notify.Firebase import notify_match
from Matching.ConcreteMatcher import StudyGroupMatcher
from Matching.ConcreteMatcher import ProjectGroupMatcher


class TaskThread:

    def __init__(self, seconds_until_next_run=None, action=None):
        if seconds_until_next_run:
            self.seconds_until_next_run = seconds_until_next_run
        else:
            def seconds():
                return 60

            self.seconds_until_next_run = seconds
        self.action = action
        self.Thread = None

    def loop(self):
        if self.action:
            self.action()
        self.start()

    def start(self):
        self.Thread = Timer(self.seconds_until_next_run(), self.loop, ())
        self.Thread.start()

    def stop(self):
        if self.Thread:
            self.Thread.cancel()


def match_creation():
    likes = db.session.query(LikeModel)
    for like in likes:
        relike = likes.filter((LikeModel.user_id == like.likes_id) & (LikeModel.likes_id == like.user_id)).first()
        if relike:
            match = MatchModel(users=[like.user, like.likes])
            chat = ChatModel.query.filter(ChatModel.users.contains(like.user),
                                          ChatModel.users.contains(like.likes)).first()
            db.session.add(match)
            db.session.delete(like)
            db.session.delete(relike)
            if not chat:
                chat = ChatModel(channel=ChannelModel())
                chat.users.extend(match.users)
                db.session.add(chat)
            db.session.commit()
            notify_match(chat)

    db.engine.execute(text(f"DELETE FROM dislikes WHERE date < '{datetime.utcnow() - timedelta(days=14)}';"))
    db.session.close()


MatchCreator = TaskThread(action=match_creation)


def next_friday():
    weekday = 4  # Friday
    hour = 14  # UTC 14:00
    next_run = datetime.utcnow()
    if next_run.hour >= hour:
        next_run += timedelta(days=1)
    next_run = next_run.replace(hour=hour, minute=0, second=0, microsecond=0)
    while next_run.weekday() is not weekday:
        next_run += timedelta(days=1)
    return (next_run - datetime.utcnow()).seconds


def study_group_matching():
    sgm = StudyGroupMatcher.StudyGroupMatcher()
    if len(sgm.query_users()) > 14:
        sgm.trigger_matching(4)
    db.session.close()


StudyGroupMatchCreator = TaskThread(seconds_until_next_run=next_friday, action=study_group_matching)


def every_day():
    hour = 16  # UTC: 16:00
    next_run = datetime.utcnow()
    if next_run.hour >= hour:
        next_run += timedelta(days=1)
    next_run = next_run.replace(hour=hour, minute=0, second=0, microsecond=0)
    return (next_run - datetime.utcnow()).seconds


def project_matching():
    matching_declarations = GroupMatchingDeclarationModel.query.all()
    for declaration in matching_declarations:
        if declaration.declared_project:
            matcher = ProjectGroupMatcher.ProjectGroupMatcher(declaration.declared_project)
            if len(matcher.query_users()) > 2:
                matcher.trigger_matching(2)
    db.session.close()


ProjectGroupMatchCreator = TaskThread(seconds_until_next_run=every_day, action=project_matching)
