import re
import sys

try:
    from datetime import timezone
except ImportError:
    from datetime import datetime
    from datetime import timedelta
    from datetime import tzinfo

    class timezone(tzinfo):
        __slots__ = "_offset", "_name"

        # Sentinel value to disallow None
        _Omitted = object()

        def __new__(cls, offset, name=_Omitted):
            if not isinstance(offset, timedelta):
                raise TypeError("offset must be a timedelta")
            if name is cls._Omitted:
                if not offset:
                    return cls.utc
                name = None
            elif not isinstance(name, str):
                raise TypeError("name must be a string")
            if not cls._minoffset <= offset <= cls._maxoffset:
                raise ValueError(
                    "offset must be a timedelta "
                    "strictly between -timedelta(hours=24) and "
                    "timedelta(hours=24)."
                )
            return cls._create(offset, name)

        @classmethod
        def _create(cls, offset, name=None):
            self = tzinfo.__new__(cls)
            self._offset = offset
            self._name = name
            return self

        def __getinitargs__(self):
            """pickle support"""
            if self._name is None:
                return (self._offset,)
            return (self._offset, self._name)

        def __eq__(self, other):
            if type(other) != timezone:
                return False
            return self._offset == other._offset

        def __hash__(self):
            return hash(self._offset)

        def __repr__(self):
            """Convert to formal string, for repr().

            >>> tz = timezone.utc
            >>> repr(tz)
            'datetime.timezone.utc'
            >>> tz = timezone(timedelta(hours=-5), 'EST')
            >>> repr(tz)
            "datetime.timezone(datetime.timedelta(-1, 68400), 'EST')"
            """
            if self is self.utc:
                return "datetime.timezone.utc"
            if self._name is None:
                return "%s.%s(%r)" % (
                    self.__class__.__module__,
                    self.__class__.__qualname__,
                    self._offset,
                )
            return "%s.%s(%r, %r)" % (
                self.__class__.__module__,
                self.__class__.__qualname__,
                self._offset,
                self._name,
            )

        def __str__(self):
            return self.tzname(None)

        def utcoffset(self, dt):
            if isinstance(dt, datetime) or dt is None:
                return self._offset
            raise TypeError(
                "utcoffset() argument must be a datetime instance" " or None"
            )

        def tzname(self, dt):
            if isinstance(dt, datetime) or dt is None:
                if self._name is None:
                    return self._name_from_offset(self._offset)
                return self._name
            raise TypeError("tzname() argument must be a datetime instance" " or None")

        def dst(self, dt):
            if isinstance(dt, datetime) or dt is None:
                return None
            raise TypeError("dst() argument must be a datetime instance" " or None")

        def fromutc(self, dt):
            if isinstance(dt, datetime):
                if dt.tzinfo is not self:
                    raise ValueError("fromutc: dt.tzinfo " "is not self")
                return dt + self._offset
            raise TypeError("fromutc() argument must be a datetime instance" " or None")

        _maxoffset = timedelta(hours=23, minutes=59)
        _minoffset = -_maxoffset

        @staticmethod
        def _name_from_offset(delta):
            if not delta:
                return "UTC"
            if delta < timedelta(0):
                sign = "-"
                delta = -delta
            else:
                sign = "+"
            hours, rest = divmod(delta, timedelta(hours=1))
            minutes, rest = divmod(rest, timedelta(minutes=1))
            seconds = rest.seconds
            microseconds = rest.microseconds
            if microseconds:
                return ("UTC{}{:02d}:{:02d}:{:02d}.{:06d}").format(
                    sign, hours, minutes, seconds, microseconds
                )
            if seconds:
                return "UTC{}{:02d}:{:02d}:{:02d}".format(sign, hours, minutes, seconds)
            return "UTC{}{:02d}:{:02d}".format(sign, hours, minutes)

    timezone.utc = timezone._create(timedelta(0))
    timezone.min = timezone._create(timezone._minoffset)
    timezone.max = timezone._create(timezone._maxoffset)


PY2 = sys.version_info[0] == 2
PY36 = sys.version_info >= (3, 6)

if PY2:
    unicode = unicode
    chr = unichr
    long = long
else:
    unicode = str
    chr = chr
    long = int


def decode(string, encodings=None):
    if not PY2 and not isinstance(string, bytes):
        return string

    if PY2 and isinstance(string, unicode):
        return string

    encodings = encodings or ["utf-8", "latin1", "ascii"]

    for encoding in encodings:
        try:
            return string.decode(encoding)
        except (UnicodeEncodeError, UnicodeDecodeError):
            pass

    return string.decode(encodings[0], errors="ignore")
