# -*- coding: utf-8 -*-
from threading import Lock
import datetime
import random
import math
from datacloud.dev_utils.logging.logger import get_basic_logger

logger = get_basic_logger(__name__)


__all__ = [
    'YdbLazySessionPool'
]


class CachedSession(object):
    __slots__ = ('_pool', '_session')

    def __init__(self, pool, session):
        self._pool = pool
        self._session = session

    def __enter__(self):
        return self._session

    def __exit__(self, *_):
        pass
        # self._pool.release(self._session)


class YdbLazySessionPool(object):
    __slots__ = ('_lazy_driver', '_session', '_session_lock', '_live_until', )

    def __init__(self, lazy_ydb_driver):
        self._lazy_driver = lazy_ydb_driver
        self._session_lock = Lock()
        self._session = None
        self._live_until = None

    def _create_session(self):
        self._session = self._lazy_driver.driver.table_client.session().create()
        self._live_until = datetime.datetime.now() + datetime.timedelta(minutes=8)

    def acquire(self):
        # TODO: Нужно обеспечить здесь максимальную надежность. Изучить эксепшены и подумать как сделать чтоб всегда работало
        # BadSession: message: "Issue during GRpc request: ExecuteDataQueryRequest" issue_code: 0 severity: 1 issue_message { message: "Session doesn\'t exist." issue_code: 0 severity: 1 }
        # with self._session_lock:
        rand_delta = datetime.timedelta(seconds=int(-math.log(random.random()) * 60 / 2))
        if self._live_until and self._live_until <= datetime.datetime.now() + rand_delta:
            logger.info('Session expired, time left: {}'.format(
                self._live_until - datetime.datetime.now()))
            try:
                self._session.delete()
            except Exception as ex:  # noqa
                logger.warn('Exception during delete', ex)
                pass
            self._session = None
        if self._session is None or self._session.session_id is None:
            self._create_session()
        return CachedSession(self, self._session)

    def release(self, session):
        pass

    @property
    def pool(self):
        return self
