import gettext as gettext_lib
from otree.common import FULL_DECIMAL_PLACES
from otree import settings
import re


# these symbols are a fallback if we don't have an explicit rule
# for the currency/language combination.
# (most common situation is where the language is English)

CURRENCY_SYMBOLS = {
    'AED': 'AED',
    'ARS': '$',
    'AUD': '$',
    'BRL': 'R$',
    'CAD': '$',
    'CHF': 'CHF',
    # need to use yuan character here, that's what gets shown
    # on form inputs. but if you run a study in english, it will
    # still show 元, which is not ideal. but that is rare.
    'CNY': '元',
    'CZK': 'Kč',
    'DKK': 'kr',
    'EGP': 'ج.م.‏',
    'EUR': '€',
    'GBP': '£',
    'HKD': 'HK$',
    'HUF': 'Ft',
    'ILS': '₪',
    'INR': '₹',
    'JPY': '円',
    'KRW': '원',
    'MXN': '$',
    'MYR': 'RM',
    'NOK': 'kr',
    'PLN': 'zł',
    'RUB': '₽',
    'SEK': 'kr',
    'SGD': 'SGD',
    'THB': 'THB',
    'TRY': '₺',
    'TWD': '$',
    'USD': '$',
    'ZAR': 'R',
}


def get_currency_format(lc: str, LO: str, CUR: str) -> str:
    '''because of all the if statements, this has very low code coverage
    but it's ok'''

    ##############################
    # Languages with complex rules
    ##############################

    if lc == 'en':
        if CUR in ['USD', 'CAD', 'AUD']:
            return '$#'
        if CUR == 'GBP':
            return '£#'
        if CUR == 'EUR':
            return '€#'
        if CUR == 'INR':
            return '₹ #'
        if CUR == 'SGD':
            return '$#'
        # override for CNY/JPY/KRW, otherwise it would be written as 원10
        # need to use the chinese character because that's already what's used in
        # form inputs
        if CUR == 'CNY':
            return '#元'
        if CUR == 'JPY':
            return '#円'
        if CUR == 'KRW':
            return '#원'
        if CUR == 'ZAR':
            return 'R#'
        return '¤#'

    if lc == 'zh':
        if CUR == 'CNY':
            return '#元'
        if CUR == 'HKD':
            return 'HK$#'
        if CUR == 'TWD':
            return '$#'
        if CUR == 'SGD':
            return 'SGD#'
        return '¤#'

    if lc == 'de':
        if CUR == 'EUR':
            if LO == 'AT':
                return '€ #'
            return '# €'
        if CUR == 'CHF':
            return 'CHF #'
        return '¤ #'

    if lc == 'es':
        if CUR == 'ARS':
            return '$ #'
        if CUR == 'EUR':
            return '# €'
        if CUR == 'MXN':
            return '$#'
        return '# ¤'

    if lc == 'nl':
        if LO == 'BE':
            if CUR == 'EUR':
                return '# €'
            return '# ¤'
        # default NL
        if CUR == 'EUR':
            return '€ #'
        return '¤ #'

    if lc == 'pt':
        if CUR == 'BRL':
            return 'R$#'
        if CUR == 'EUR':
            return '# €'
        return '¤#'

    if lc == 'ar':
        if CUR == 'AED':
            return 'د.إ.‏ #'
        return '¤ #'

    #############################
    # Languages with simple rules
    #############################

    if lc == 'cs':
        if CUR == 'CZK':
            return '# Kč'
        return '# ¤'
    if lc == 'da':
        if CUR == 'DKK':
            return '# kr.'
        return '# ¤'
    if lc == 'fi':
        if CUR == 'EUR':
            return '# €'
        return '# ¤'
    if lc == 'fr':
        if CUR == 'EUR':
            return '# €'
        return '# ¤'
    if lc == 'he':
        if CUR == 'ILS':
            return '# ₪'
        return '# ¤'
    if lc == 'hu':
        if CUR == 'HUF':
            return '# Ft'
        return '# ¤'
    if lc == 'it':
        if CUR == 'EUR':
            return '# €'
        return '# ¤'
    if lc == 'ja':
        if CUR == 'JPY':
            return '#円'
        return '¤#'
    if lc == 'ko':
        if CUR == 'KRW':
            return '#원'
        return '¤#'
    if lc == 'ms':
        if CUR == 'MYR':
            return 'RM#'
        return '¤#'
    if lc == 'nb':
        if CUR == 'NOK':
            return 'kr #'
        return '¤ #'
    if lc == 'pl':
        if CUR == 'PLN':
            return '# zł'
        return '# ¤'
    if lc == 'ru':
        if CUR == 'RUB':
            return '# ₽'
        return '# ¤'
    if lc == 'sv':
        if CUR == 'SEK':
            return '# kr'
        return '# ¤'
    if lc == 'th':
        if CUR == 'THB':
            return '฿#'
        return '¤#'
    if lc == 'tr':
        if CUR == 'TRY':
            return '# ₺'
        return '# ¤'
    if lc == 'hi':
        if CUR == 'INR':
            return '₺#'
        return '¤#'

    # fallback if it's another language, etc.
    return '# ¤'


# def format_number(number, *, places):
#     """we don't use locale.setlocale because e.g.
#     only english locale is installed on heroku
#
#     This is a complex function because it's is used by many different things.
#     - formatting any number (random floats, etc)
#     - forms
#     - to0, to1, to2
#
#     """
#     # we use FULL_DECIMAL_PLACES as the arg because it's more explict than None.
#     if places is FULL_DECIMAL_PLACES:
#         places = None
#     str_number = str(number)
#     if '.' in str_number:
#         lhs, rhs = str_number.split('.')
#     else:
#         lhs = str_number
#         if places is None:
#             return lhs
#         rhs = ''
#     if places is not None:
#         rhs = rhs.ljust(places, '0')
#     if places == 0:
#         return lhs
#     # rhs[:None] just takes the whole thing, which is the desired behavior
#     # with floats.
#     return lhs + settings.DECIMAL_SEPARATOR + rhs[:places]


def _convert_decimal_separator_char(c):
    # need to do it in 1 pass
    if c == ',':
        return settings.THOUSAND_SEPARATOR
    if c == '.':
        return settings.DECIMAL_SEPARATOR
    return c


def convert_decimal_separator(num_str):
    return ''.join(_convert_decimal_separator_char(c) for c in num_str)


def format_number(number, *, places):
    if places == FULL_DECIMAL_PLACES:
        fmt = "{:,}"
    else:
        fmt = "{:,.%df}" % places
    res = fmt.format(number)
    return convert_decimal_separator(res)


def format_number_for_form(number, *, places):
    if places == FULL_DECIMAL_PLACES:
        fmt = "{}"
    else:
        fmt = "{:.%df}" % places
    res = fmt.format(number)
    return convert_decimal_separator(res)


def extract_otreetemplate(fileobj, keywords, comment_tags, options):
    """Deprecated"""
    for lineno, line in enumerate(fileobj, start=1):
        for msg in re.findall(r"""\{\{\s?trans ['"](.*)['"]\s?\}\}""", line.decode()):
            yield (lineno, 'trans', msg, [])


def extract_otreetemplate_internal(fileobj, keywords, comment_tags, options):
    """babel custom extractor for |gettext in otree templates"""
    for lineno, line in enumerate(fileobj, start=1):
        for msg in re.findall(
            r"""\{\{\s?['"](.*)['"]\|gettext\s?\}\}""", line.decode()
        ):
            # not sure exactly what the 2nd arg is for
            yield (lineno, 'gettext', msg, [])


def core_gettext(msg):
    return gettext_lib.dgettext('django', msg)


"""
Don't use core-ngettext because pybabel doesn't recognize that it is for
plurals 
"""
