import uuid
import logging

from .storage import SessionStorage
from .cookies import CookieSessionMixIn


L = logging.getLogger(__name__)


class InMemorySessionStorage(SessionStorage, CookieSessionMixIn):
    def __init__(self, app, session_class, max_age=60 * 15, cookie_name="SESSID"):
        super().__init__(app, max_age=max_age, session_class=session_class)
        self.set_cookie_name(cookie_name)

        self.Sessions = {}

        app.PubSub.subscribe("Application.tick/10!", self._on_tick)

    async def load(self, request):
        session_id = self.get_session_id_from_request(request)
        if session_id is not None:
            session = self.Sessions.get(session_id)
            if session is not None:
                if session.is_expired():
                    session = None
                else:
                    return session

            L.warning("Invalid session id '{}'".format(session_id))

        return await self.create(request)

    async def set(self, session, response):
        if session.is_new():
            while True:
                session_id = uuid.uuid4().hex
                if session_id not in self.Sessions:
                    session.set_id(session_id)
                    break

            self.Sessions[session.Id] = session
            self.set_session_to_response(session, response)

    async def delete(self, session):
        session_p = self.Sessions.pop(session.Id)
        assert session_p == session

    async def store(self, session):
        session.reset()

    async def _on_tick(self, message_type):
        # Find expired session and remove them
        expired_sessions = []
        for session in self.Sessions.values():
            if session.is_expired():
                expired_sessions.append(session)

        for session in expired_sessions:
            await self.delete(session)
