import threading
from datetime import datetime, timedelta
from sqlalchemy import DateTime, cast, func
from flask import current_app
from bot.reminders import add_reservation_reminder, remove_reservation_reminder, update_reservation_reminder
from app import db
from app.models import Reservation
from .lock import Lock
from .free_workplaces import FreeWorkplacesController
from ..exceptions import ReservationExpiredError, NoFreeWorkplaceError, UserNotConfirmedError, UserBlockedError

class ReservationController():
    workplaces_lock = Lock.workplaces_lock

    @classmethod
    def create(cls, user):
        with cls.workplaces_lock:
            FreeWorkplacesController.check_free_workplaces()

            if not user.is_confirmed:
                raise UserNotConfirmedError

            if user.is_blocked:
                raise UserBlockedError

            reservation = Reservation()
            reservation.user = user
            reservation.time_start = datetime.now()
            reservation.time_end = datetime.now() + current_app.config.get('RESERVATION_DURATION', timedelta(hours=1))

            db.session.add(reservation)
            db.session.commit()

            add_reservation_reminder(reservation)

            return reservation


    @classmethod
    def extend(cls, reservation):
        with cls.workplaces_lock:
            user = reservation.user

            if not user.is_confirmed:
                raise UserNotConfirmedError

            if user.is_blocked:
                raise UserBlockedError

            reservation.time_end = datetime.now() + current_app.config.get('RESERVATION_DURATION', timedelta(hours=1))
            db.session.commit()

            update_reservation_reminder(reservation)


    @staticmethod
    def get(reservation_id):
        return Reservation.query.get(reservation_id)


    @classmethod
    def has_active_reservation(cls, user):
        return cls.get_active_reservation(user) is not None


    @staticmethod
    def get_active_reservation(user):
        now = datetime.now()
        return Reservation.query \
            .filter(cast(Reservation.time_start,DateTime) <= now) \
            .filter(cast(Reservation.time_end,DateTime) > now) \
            .filter(Reservation.user_id == user._id) \
            .first()


    @staticmethod
    def get_all_active_reservations():
        now = datetime.now()
        return Reservation.query \
            .filter(cast(Reservation.time_start,DateTime) <= now) \
            .filter(cast(Reservation.time_end,DateTime) > now) \
            .all()


    @classmethod
    def cancel(cls, reservation):
        with cls.workplaces_lock:
            reservation.time_end = datetime.now()
            db.session.commit()

            remove_reservation_reminder(reservation)