from math import modf
import pymorphy2
from pymorphy2.shapes import restore_capitalization

CURRENCY_CODE_2_NAME_MAP = {
    "USD": "доллар США",
    "EUR": "евро",
    "RUR": "рубль",
    "RUB": "рубль",
    "CNY": "юань",
    "GBP": "фунт стерлингов",
    "JPY": "иена",
    "CHF": "швейцарский франк",
    "CAD": "канадский доллар",
    "SGD": "сингапурский доллар",
    "HKD": "гонконгский доллар",
    "DKK": "датская крона",
    "NOK": "норвежская крона",
    "SEK": "шведская крона",
    "AUD": "австралийский доллар",
    "UAH": "украинская гривна",
    "AZN": "азербайджанский манат",
    "DZD": "алжирский динар",
    "ARS": "аргентинское песо",
    "AMD": "армянский драм",
    "AWG": "арубанский флорин",
    "AFN": "афгани",
    "PAB": "бальбоа",
    "BBD": "барбадосский доллар",
    "THB": "таиландский бат",
    "BHD": "бахрейнский динар",
    "BZD": "белизский доллар",
    "BYN": "белорусский рубль",
    "BMD": "бермудский доллар",
    "BGN": "болгарский лев",
    "VES": "венесуэльский боливар соберано",
    "BOB": "боливиано",
    "BRL": "бразильский реал",
    "BND": "брунейский доллар",
    "BIF": "бурундийский франк",
    "VUV": "вату",
    "KRW": "вона",
    "XCD": "восточно-карибский доллар",
    "GYD": "гайанский доллар",
    "GHS": "ганский седи",
    "GNF": "гвинейский франк",
    "GIP": "гибралтарский фунт",
    "PYG": "гуарани",
    "HTG": "гурд",
    "GMD": "даласи",
    "MKD": "македонский денар",
    "JEP": "джерсийский фунт",
    "AED": "дирхам ОАЭ",
    "STN": "добра",
    "ZWL": "доллар зимбабве",
    "NAD": "доллар намибии",
    "KYD": "доллар островов кайман",
    "SBD": "доллар Cоломоновых островов",
    "TTD": "доллар Тринидада и Тобаго",
    "FJD": "доллар Фиджи",
    "DOP": "доминиканское песо",
    "VND": "донг",
    "EGP": "египетский фунт",
    "COU": "единица реальной стоимости",
    "ZMW": "замбийская квача",
    "PLN": "польский злотый",
    "NIO": "никарагуанская золотая кордоба",
    "INR": "индийская рупия",
    "JOD": "иорданский динар",
    "IQD": "иракский динар",
    "IRR": "иранский риал",
    "ISK": "исландская крона",
    "YER": "йеменский риал",
    "QAR": "катарский риал",
    "AOA": "ангольская кванза",
    "KES": "кенийский шиллинг",
    "GTQ": "гватемальский кетсаль",
    "PGK": "кина",
    "COP": "колумбийское песо",
    "KMF": "коморский франк",
    "BAM": "конвертируемая марка",
    "CUC": "конвертируемое песо",
    "CDF": "конголезский франк",
    "CRC": "коста-риканский колон",
    "CUP": "кубинское песо",
    "KWD": "кувейтский динар",
    "HRK": "хорватская куна",
    "MMK": "кьят",
    "LAK": "лаосский кип",
    "GEL": "грузинский лари",
    "ALL": "албанский лек",
    "HNL": "гондурасская лемпира",
    "SLL": "леоне",
    "LRD": "либерийский доллар",
    "LBP": "ливанский фунт",
    "LYD": "ливийский динар",
    "SZL": "лилангени",
    "LSL": "лоти",
    "MUR": "маврикийская рупия",
    "MWK": "малавийская квача",
    "MGA": "малагасийский ариари",
    "MYR": "малайзийский ринггит",
    "MAD": "марокканский дирхам",
    "MXN": "мексиканское песо",
    "MZN": "мозамбикский метикал",
    "MDL": "молдавский лей",
    "NGN": "найра",
    "ERN": "накфа",
    "BTN": "нгултрум",
    "NPR": "непальская рупия",
    "ANG": "нидерландский антильский гульден",
    "NZD": "новозеландский доллар",
    "ILS": "новый израильский шекель",
    "TWD": "новый тайваньский доллар",
    "TMT": "новый туркменский манат",
    "OMR": "оманский риал",
    "TOP": "паанга",
    "PKR": "пакистанская рупия",
    "MOP": "патака",
    "BWP": "пула",
    "KHR": "риель",
    "RON": "румынский лей",
    "IDR": "индонезийская рупия",
    "MVR": "мальдивская руфия",
    "ZAR": "южноафриканский рэнд",
    "SVC": "сальвадорский колон",
    "SAR": "саудовский риял",
    "KPW": "северокорейская вона",
    "SCR": "сейшельская рупия",
    "RSD": "сербский динар",
    "SYP": "сирийский фунт",
    "PEN": "перуанский соль",
    "KGS": "киргизский сом",
    "SOS": "сомалийский шиллинг",
    "TJS": "сомони",
    "SDG": "суданский фунт",
    "SRD": "суринамский доллар",
    "BDT": "бангладешская така",
    "WST": "тала",
    "TZS": "танзанийский шиллинг",
    "KZT": "казахстанский тенге",
    "MNT": "монгольский тугрик",
    "TND": "тунисский динар",
    "TRY": "турецкая лира",
    "UGX": "угандийский шиллинг",
    "MRU": "мавританская угия",
    "UZS": "узбекский сум",
    "UYU": "уругвайское песо",
    "PHP": "филиппинское песо",
    "HUF": "венгерский форинт",
    "DJF": "франк джибути",
    "XAF": "франк КФА ВЕАС",
    "XOF": "франк КФА ВСЕАО",
    "XPF": "франк КФП",
    "RWF": "франк Руанды",
    "IMP": "фунт Острова Мэн",
    "SHP": "фунт Святой Елены",
    "FKP": "фунт Фолклендских островов",
    "CZK": "чешская крона",
    "CLP": "чилийское песо",
    "LKR": "шри-ланкийская рупия",
    "CVE": "эскудо Кабо-Верде",
    "ETB": "эфиопский быр",
    "SSP": "южносуданский фунт",
    "JMD": "ямайский доллар",
    "XDR": "специальные права заимствования",
    "DEM": "немецкая марка",
    "ITL": "итальянская лира",
    "LVL": "латвийский лат",
    "ATS": "австрийский шиллинг",
    "ESP": "испанская песета",
    "FRF": "французский франк",
    "BEF": "бельгийский франк",
    "GRD": "греческая драхма",
    "IEP": "ирландский фунт",
    "LTL": "литовский лит",
    "CYP": "кипрский фунт",
    "LUF": "люксембургский франк",
    "MTL": "мальтийская лира",
    "NLG": "голландский гульден",
    "PTE": "португальское эскудо",
    "FIM": "финская марка",
    "ADP": "андоррская песета",
    "MTP": "мальтийский фунт",
    "SKK": "словацкая крона",
    "SIT": "словенский толар",
    "YUM": "югославский динар",
    "EEK": "эстонская крона",
    "GWE": "гвинейский эскудо",
    "GWP": "песо Гвинеи-Бисау",
    "MLF": "малийский франк",
    "TPE": "тиморское эскудо",
    "ECS": "сукре",
    "ARA": "аргентинский аустраль",
    "BOP": "боливийское песо",
    "BAD": "динар Боснии и Герцеговины",
    "BRC": "крузадо",
    "BRN": "новый крузадо",
    "BRE": "крузейро",
    "BRR": "крузейро реал",
    "GNS": "сили",
    "ZRZ": "заир",
    "ZRN": "новый заир",
    "ILP": "израильский фунт",
    "YDD": "йеменский динар",
    "MGF": "малагасийский франк",
    "MZE": "мозамбикский эскудо",
    "SDD": "суданский динар",
    "SRG": "суринамский гульден",
    "TJR": "таджикский рубль",
    "UAK": "карбованец",
    "HRD": "хорватский динар",
    "SUR": "советский рубль"
}

CURRENCY_CODE_2_DEMUNITIVE_NAME_MAP = {
    "USD": "цент",
    "EUR": "евроцент",
    "RUR": "копейка",
    "SEK": "эре",
    "DKK": "эре",
    "NOK": "эре",
    "GBP": "пенс",
    "CHF": "сантим",
    "CAD": "цент",
    "AUD": "цент",
    "SGD": "цент",
    "JPY": "сен",
    "CNY": "фынь",
    "UAH": "копейка",
    "BYN": "копейка",
    "CZK": "геллер",
    "EGP": "пиастр",
    "TRY": "куруш",
    "GEL": "тетри",
    "AMD": "лум",
    "AED": "филс",
    "AFN": "пул",
    "ALL": "киндарка",
    "ANG": "цент",
    "AOA": "сентимо",
    "ARS": "сентаво",
    "AWG": "цент",
    "AZN": "гяпик",
    "BAM": "фенинг",
    "BBD": "цент",
    "BDT": "пойша",
    "BGN": "стотинка",
    "BIF": "сантим",
    "BMD": "цент",
    "BND": "сен",
    "BOB": "сентаво",
    "BRL": "сентаво",
    "BTN": "четрум",
    "BWP": "тхебе",
    "BZD": "цент",
    "CDF": "сантим",
    "CLP": "сентаво",
    "COP": "сентаво",
    "CRC": "сентимо",
    "CUC": "сентаво",
    "CUP": "сентаво",
    "CVE": "сентаво",
    "DJF": "сантим",
    "DOP": "сентаво",
    "DZD": "сантим",
    "ERN": "цент",
    "ETB": "цент",
    "FJD": "цент",
    "FKP": "пенс",
    "GHS": "песева",
    "GIP": "пенс",
    "GMD": "бутут",
    "GNF": "сантим",
    "GTQ": "сентаво",
    "GYD": "цент",
    "HKD": "цент",
    "HNL": "сентаво",
    "HRK": "липа",
    "HTG": "сантим",
    "HUF": "филлер",
    "IDR": "сен",
    "ILS": "агор",
    "IMP": "пенс",
    "INR": "пайса",
    "IRR": "динар",
    "JEP": "пенс",
    "JMD": "цент",
    "JOD": "пиастр",
    "KES": "цент",
    "KGS": "тыйын",
    "KHR": "сен",
    "KMF": "сантим",
    "KPW": "чон",
    "KRW": "чон",
    "KYD": "цент",
    "KZT": "тиын",
    "LAK": "ат",
    "LBP": "пиастр",
    "LKR": "цент",
    "LRD": "цент",
    "LSL": "сенте",
    "MAD": "сантим",
    "MDL": "бань",
    "MKD": "дени",
    "MMK": "пья",
    "MNT": "мунгу",
    "MOP": "аво",
    "MUR": "цент",
    "MVR": "лари",
    "MWK": "тамбала",
    "MXN": "сентаво",
    "MYR": "сен",
    "MZN": "сентаво",
    "NAD": "цент",
    "NGN": "кобо",
    "NIO": "сентаво",
    "NPR": "пайса",
    "NZD": "цент",
    "OMR": "байза",
    "PAB": "сентесимо",
    "PEN": "сентимо",
    "PGK": "тойя",
    "PHP": "сентимо",
    "PKR": "пайса",
    "PLN": "грош",
    "PYG": "сентимо",
    "QAR": "дирхам",
    "RON": "бань",
    "RSD": "пара",
    "RWF": "cантим",
    "SAR": "халал",
    "SBD": "цент",
    "SCR": "цент",
    "SDG": "пиастр",
    "SHP": "пенс",
    "SLL": "цент",
    "SOS": "цент",
    "SRD": "цент",
    "SSP": "пиастр",
    "STM": "сентимо",
    "SVC": "сентаво",
    "SYP": "пиастр",
    "SZL": "цент",
    "THB": "сатанг",
    "TJS": "дирам",
    "TMT": "тенге",
    "TOP": "сенити",
    "TTD": "цент",
    "TWD": "фынь",
    "TZS": "цент",
    "UGX": "цент",
    "UYU": "сентесимо",
    "UZS": "тийин",
    "VES": "сентимо",
    "VND": "су",
    "WST": "сене",
    "XAF": "сантим",
    "XCD": "цент",
    "XOF": "сантим",
    "XPF": "сантим",
    "YER": "филс",
    "ZAR": "цент",
    "ZMW": "нгве",
    "ZWL": "цент"
}


class Money2Text:
    def __init__(self, morph=None):
        self.morph = pymorphy2.MorphAnalyzer() if morph is None else morph

    def for_special_cases(self, whole, frac, whole_name, frac_name):
        right_whole_name = self.right_text_spelling_with_number(whole, whole_name)
        right_frac_name = self.right_text_spelling_with_number(frac, frac_name)
        return "{:.0f} {} {:.0f} {}".format(whole, right_whole_name, frac, right_frac_name)

    def right_text_spelling_with_number(self, number, text):
        agreed = []
        for token in text.split():
            parse_result = self.morph.parse(token)
            for option in parse_result:
                if option.normal_form == token:
                    word = option
                    break
            else:
                word = parse_result[0]

            agreed_Parse_obj = word.make_agree_with_number(number)
            agreed.append(restore_capitalization(agreed_Parse_obj.word, token) if agreed_Parse_obj else token)
        return " ".join(agreed)

    def _right_word_spelling_with_number(self, number, word):
        butyavka = self.morph.parse(word)[0]
        return butyavka.make_agree_with_number(number).word

    def __call__(self, amount, currency):
        precision = 2
        currency = currency.upper()
        amount = round(amount, precision)
        if currency not in CURRENCY_CODE_2_NAME_MAP:
            return '{} {}'.format(round(amount, 2), currency)

        name = CURRENCY_CODE_2_NAME_MAP[currency]

        frac, whole = modf(amount)
        frac = round(frac, precision) * 100
        if currency in CURRENCY_CODE_2_DEMUNITIVE_NAME_MAP.keys():
            if frac != 0:
                frac_name = CURRENCY_CODE_2_DEMUNITIVE_NAME_MAP[currency]
                return self.for_special_cases(whole=whole, whole_name=name, frac=frac, frac_name=frac_name)
            else:
                return '{0:.0f}'.format(amount) + " " + self.right_text_spelling_with_number(amount, name)
        else:
            if frac == 0:
                return '{0:.0f}'.format(amount) + " " + self.right_text_spelling_with_number(amount, name)
            else:
                return '{}'.format(round(amount, 2)) + " " + self.right_text_spelling_with_number(amount, name)
