from contextlib import ContextDecorator
from contextlib import contextmanager
from zope.globalrequest import getRequest

import datetime
import os
import sys
import time
import unittest

missing_value = object()

PY_311_OR_MORE = sys.version_info >= (3, 11)


@contextmanager
def indexing_disabled(request=missing_value):
    """Context manager that temporarily disables the indexing queue
    The queue is restored to its previous state
    after the context manager exits.

    yields the request object
    """
    if request is missing_value:
        request = getRequest()

    try:
        old_value = request["disable-indexing"]
    except Exception:
        # Either key is not there or this is not a dict-like
        old_value = missing_value

    try:
        try:
            request["disable-indexing"] = True
        except Exception:
            # Probably the object is not dict-like
            pass
        yield request
    finally:
        if old_value == missing_value:
            try:
                # Either key is not there or this is not dict-like
                getattr(request, "other", request).pop("disable-indexing")
            except Exception:
                pass
        else:
            request["disable-indexing"] = old_value


class disabled(ContextDecorator):
    """Temporarily sets a flag request[feature] = value on the request object.

    The original value of request[self.feature] is saved and restored after the
    context manager exits.
    """

    value = object()
    _old_value = missing_value

    def __init__(self, feature, request=None):
        self.feature = feature
        self.default_request = request

    def __enter__(self):
        request = self.get_request()
        try:
            self._old_value = request[self.feature]
        except Exception:
            pass

        try:
            request[self.feature] = self.value
        except Exception:
            # Probably the object is not dict-like
            pass
        return self

    def __exit__(self, *exc):
        request = self.get_request()
        if self._old_value == missing_value:
            try:
                # Either key is not there or this is not dict-like
                getattr(request, "other", request).pop(self.feature)
            except Exception:
                pass
        else:
            request[self.feature] = self._old_value

        self._old_value = missing_value

    def get_request(self):
        return self.default_request or getRequest()


def is_disabled(feature, request=None):
    """Check if feature is disabled for the request."""
    if not request:
        request = getRequest()
    try:
        return request[feature] is disabled.value
    except Exception:
        return False


def is_enabled(feature, request=None):
    """Check if feature is enabled for the request."""
    return not is_disabled(feature, request)


@contextmanager
def system_timezone_CET():
    """Temporarily set the OS timezone to CET

    >>> with system_timezone_CET():
    ...   datetime.datetime.now()
    ...   datetime.datetime.now().astimezone()
    ...
    datetime.datetime(2023, 11, 21, 15, 51, 15, 673294)
    datetime.datetime(2023, 11, 21, 15, 51, 15, 673385, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))

    # Outside the context manager, falls back to OS zone (Europe/Istanbul):

    >>> datetime.datetime.now()
    datetime.datetime(2023, 11, 21, 17, 51, 19, 913653)
    >>> datetime.datetime.now().astimezone()
    datetime.datetime(2023, 11, 21, 17, 51, 24, 692034, tzinfo=datetime.timezone(datetime.timedelta(seconds=10800), '+03'))
    """  # noqa
    timetz = time.tzname
    ostz = "TZ" in os.environ.keys() and os.environ["TZ"] or None
    os.environ["TZ"] = "Europe/Amsterdam"
    time.tzname = ("CET", "CEST")
    time.tzset()
    CET = datetime.timezone(datetime.timedelta(seconds=3600), "CET")
    try:
        # enable running wintertime tests in summer
        with unittest.mock.patch(
            "ploneintranet.notifications.sql.saconfig.local_timezone", return_value=CET
        ):
            yield CET
    finally:
        time.tzname = timetz
        if ostz:
            os.environ["TZ"] = ostz
        else:
            del os.environ["TZ"]
        time.tzset()


@contextmanager
def system_timezone_CEST():
    """Temporarily set the OS timezone to CEST"""
    timetz = time.tzname
    ostz = "TZ" in os.environ.keys() and os.environ["TZ"] or None
    os.environ["TZ"] = "Europe/Amsterdam"
    time.tzname = ("CET", "CEST")
    time.tzset()
    CEST = datetime.timezone(datetime.timedelta(seconds=7200), "CEST")
    try:
        # enable running summertime tests in winter
        with unittest.mock.patch(
            "ploneintranet.notifications.sql.saconfig.local_timezone", return_value=CEST
        ):
            yield CEST
    finally:
        time.tzname = timetz
        if ostz:
            os.environ["TZ"] = ostz
        else:
            del os.environ["TZ"]
        time.tzset()
