#
# This file is part of SickGear.
#
# SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickGear.  If not, see <http://www.gnu.org/licenses/>.

import os
import logging
import locale
import sys

from six import iteritems, moves, PY2, text_type, string_types

logger = logging.getLogger('encodingKludge')
logger.addHandler(logging.NullHandler())

# noinspection PyUnreachableCode
if False:
    # noinspection PyUnresolvedReferences
    from typing import AnyStr

SYS_ENCODING = None
EXIT_BAD_ENCODING = None


def set_sys_encoding():
    # type: (...) -> (bool, AnyStr)
    """Set system encoding

    :return: The encoding that is set
    """
    should_exit = False
    try:
        locale.setlocale(locale.LC_ALL, '')
    except (locale.Error, IOError):
        pass
    try:
        sys_encoding = locale.getpreferredencoding()
    except (locale.Error, IOError):
        sys_encoding = None

    # For OSes that are poorly configured I'll just randomly force UTF-8
    if not sys_encoding or sys_encoding in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
        sys_encoding = 'UTF-8'

    if not hasattr(sys, 'setdefaultencoding'):
        moves.reload_module(sys)

    if PY2:
        try:
            # On non-unicode builds this raises an AttributeError,
            # if encoding type is not valid it throws a LookupError
            # noinspection PyUnresolvedReferences
            sys.setdefaultencoding(sys_encoding)
        except (BaseException, Exception):
            should_exit = True

    return should_exit, sys_encoding


if None is EXIT_BAD_ENCODING:
    EXIT_BAD_ENCODING, SYS_ENCODING = set_sys_encoding()

# This module tries to deal with the apparently random behavior of python when dealing with unicode <-> utf-8
# encodings. It tries to just use unicode, but if that fails then it tries forcing it to utf-8. Any functions
# which return something should always return unicode.


# noinspection PyCompatibility,PyPep8Naming
def fixStupidEncodings(x, silent=False):
    if not PY2:
        return x

    if str == type(x):
        try:
            return x.decode(SYS_ENCODING)
        except UnicodeDecodeError:
            logger.error(u"Unable to decode value: " + repr(x))
    elif text_type == type(x):
        return x
    else:
        msg = u"Unknown value passed in, ignoring it: " + str(type(x)) + " (" + repr(x) + ":" + repr(type(x)) + ")"
        if silent:
            logger.debug(msg)
        else:
            logger.error(msg)


# noinspection PyCompatibility,PyPep8Naming
def fixOutEncoding(x):
    if PY2 and isinstance(x, string_types):
        return fixStupidEncodings(x)
    return x


# noinspection PyCompatibility,PyPep8Naming
def fixListEncodings(x):
    if not PY2 or type(x) not in (list, tuple):
        return x
    return filter(lambda i: None is not i, map(fixOutEncoding, x))


# noinspection PyCompatibility,PyPep8Naming
def callPeopleStupid(x):
    if not PY2:
        return x

    try:
        return x.encode(SYS_ENCODING)
    except UnicodeEncodeError:
        logger.error(u'Your data is being corrupted by a bad locale/encoding setting.'
                     u' Report this error in IRC please: %s, %s' % (repr(x), SYS_ENCODING))
        return x.encode(SYS_ENCODING, 'ignore')


# noinspection PyCompatibility,PyPep8Naming
def fixParaLists(x):
    if PY2 and list == type(x):
        return [callPeopleStupid(a) if type(a) in (str, text_type) else a for a in x]
    return x


# noinspection PyCompatibility
def win_encode_unicode(x):
    if PY2 and isinstance(x, str):
        try:
            # noinspection PyUnresolvedReferences
            return x.decode('UTF-8')
        except UnicodeDecodeError:
            pass
    return x


# noinspection PyCompatibility
def ek(func, *args, **kwargs):
    if not PY2:
        return func(*args, **kwargs)
    if 'nt' == os.name:
        # convert all str parameter values to unicode
        args = tuple([x if not isinstance(x, str) else win_encode_unicode(x) for x in args])
        # iteritems can stay, since this code will not run on py3
        kwargs = {k: x if not isinstance(x, str) else win_encode_unicode(x) for k, x in iteritems(kwargs)}
        result = func(*args, **kwargs)
    else:
        result = func(*[callPeopleStupid(x) if type(x) in (str, text_type)
                        else fixParaLists(x) for x in args], **kwargs)

    if type(result) in (list, tuple):
        return fixListEncodings(result)
    elif type(result) == str:
        return fixStupidEncodings(result)
    return result
