# Copyright (c) 2003, Taro Ogawa.  All Rights Reserved.
# Copyright (c) 2013, Savoir-faire Linux inc.  All Rights Reserved.
# Copyright (c) 2022, Sergei Ruzki.  All Rights Reserved.

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# This library 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
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA

from __future__ import unicode_literals

from .base import Num2Word_Base
from .utils import get_digits, splitbyx

ZERO = "нуль"

ONES_FEMININE = {
    1: "адна",
    2: "дзве",
    3: "тры",
    4: "чатыры",
    5: "пяць",
    6: "шэсць",
    7: "сем",
    8: "восем",
    9: "дзевяць",
}

ONES = {
    "f": {
        1: "адна",
        2: "дзве",
        3: "тры",
        4: "чатыры",
        5: "пяць",
        6: "шэсць",
        7: "сем",
        8: "восем",
        9: "дзевяць",
    },
    "m": {
        1: "адзін",
        2: "два",
        3: "тры",
        4: "чатыры",
        5: "пяць",
        6: "шэсць",
        7: "сем",
        8: "восем",
        9: "дзевяць",
    },
    "n": {
        1: "адно",
        2: "два",
        3: "тры",
        4: "чатыры",
        5: "пяць",
        6: "шэсць",
        7: "сем",
        8: "восем",
        9: "дзевяць",
    },
}

TENS = {
    0: "дзесяць",
    1: "адзінаццаць",
    2: "дванаццаць",
    3: "трынаццаць",
    4: "чатырнаццаць",
    5: "пятнаццаць",
    6: "шаснаццаць",
    7: "сямнаццаць",
    8: "васямнаццаць",
    9: "дзевятнаццаць",
}

TWENTIES = {
    2: "дваццаць",
    3: "трыццаць",
    4: "сорак",
    5: "пяцьдзясят",
    6: "шэсцьдзясят",
    7: "семдзесят",
    8: "восемдзесят",
    9: "дзевяноста",
}

TWENTIES_ORD = (
    ("дваццаць", "дваццаці"),
    ("трыццаць", "трыццаці"),
    ("сорак", "сарака"),
    ("пяцьдзясят", "пяцідзясяці"),
    ("шэсцьдзясят", "шaсцідзясяці"),
    ("семдзесят", "сямідзесяці"),
    ("восемдзесят", "васьмідзесяці"),
    ("дзевяноста", "дзевяноста"),
)

HUNDREDS = {
    1: "сто",
    2: "дзвесце",
    3: "трыста",
    4: "чатырыста",
    5: "пяцьсот",
    6: "шэсцьсот",
    7: "семсот",
    8: "восемсот",
    9: "дзевяцьсот",
}

THOUSANDS = {
    1: ("тысяча", "тысячы", "тысяч"),  # 10^3
    2: ("мільён", "мільёны", "мільёнаў"),  # 10^6
    3: ("мільярд", "мільярды", "мільярдаў"),  # 10^9
    4: ("трыльён", "трыльёны", "трыльёнаў"),  # 10^12
    5: ("квадрыльён", "квадрыльёны", "квадрыльёнаў"),  # 10^15
    6: ("квінтыльён", "квінтыльёны", "квінтыльёнаў"),  # 10^18
    7: ("секстыльён", "секстыльёны", "секстыльёнаў"),  # 10^21
    8: ("сэптыльён", "сэптыльёны", "сэптыльёнаў"),  # 10^24
    9: ("актыльён", "актыльёны", "актыльёнаў"),  # 10^27
    10: ("нанільён", "нанільёны", "нанільёнаў"),  # 10^30
}


class Num2Word_BE(Num2Word_Base):
    CURRENCY_FORMS = {
        "RUB": (
            ("расійскі рубель", "расійскія рублі", "расійскіх рублёў"),
            ("капейка", "капейкі", "капеек"),
        ),
        "EUR": (("еўра", "еўра", "еўра"), ("цэнт", "цэнты", "цэнтаў")),
        "USD": (("долар", "долары", "долараў"), ("цэнт", "цэнты", "цэнтаў")),
        "UAH": (
            ("грыўна", "грыўны", "грыўнаў"),
            ("капейка", "капейкі", "капеек"),
        ),
        "KZT": (("тэнге", "тэнге", "тэнге"), ("тыйін", "тыйіны", "тыйінаў")),
        "BYN": (
            ("беларускі рубель", "беларускія рублі", "беларускіх рублёў"),
            ("капейка", "капейкі", "капеек"),
        ),
        "UZS": (("сум", "сумы", "сумаў"), ("тыйін", "тыйіны", "тыйінаў")),
        "PLN": (("злоты", "злотых", "злотых"), ("грош", "грошы", "грошаў")),
    }

    def setup(self):
        self.negword = "мінус"
        self.pointword = "коска"
        self.ords = {
            "нуль": "нулявы",
            "адзін": "першы",
            "два": "другі",
            "тры": "трэці",
            "чатыры": "чацвёрты",
            "пяць": "пяты",
            "шэсць": "шосты",
            "сем": "сёмы",
            "восем": "восьмы",
            "дзевяць": "дзявяты",
            "сто": "соты",
            "тысяча": "тысячны",
        }

        self.ords_adjective = {
            "адзін": "адна",
            "адна": "адна",
            "дзве": "двух",
            "тры": "трох",
            "чатыры": "чатырох",
            "пяць": "пяці",
            "шэсць": "шасці",
            "сем": "сямі",
            "восем": "васьмі",
            "дзевяць": "дзевяцi",
            "сто": "ста",
        }

    def to_cardinal(self, number, gender="m"):
        n = str(number).replace(",", ".")
        if "." in n:
            left, right = n.split(".")
            if set(right) == {"0"}:
                leading_zero_count = 0
            else:
                leading_zero_count = len(right) - len(right.lstrip("0"))

            decimal_part = (ZERO + " ") * leading_zero_count + self._int2word(
                int(right), gender
            )
            return "{} {} {}".format(
                self._int2word(int(left), gender), self.pointword, decimal_part
            )
        else:
            return self._int2word(int(n), gender)

    def pluralize(self, n, forms):
        if n % 100 < 10 or n % 100 > 20:
            if n % 10 == 1:
                form = 0
            elif 5 > n % 10 > 1:
                form = 1
            else:
                form = 2
        else:
            form = 2
        return forms[form]

    def to_ordinal(self, number, gender="m"):
        self.verify_ordinal(number)
        if isinstance(gender, bool) and gender:
            gender = "f"
        outwords = self.to_cardinal(number, gender).split(" ")
        lastword = outwords[-1].lower()
        try:
            if len(outwords) > 1:
                if outwords[-2] in self.ords_adjective:
                    outwords[-2] = self.ords_adjective.get(
                        outwords[-2], outwords[-2]
                    )
                elif outwords[-2] == "дзесяць":
                    outwords[-2] = outwords[-2][:-1] + "і"
            if len(outwords) == 3:
                if outwords[-3] in ["адзін", "адна"]:
                    outwords[-3] = ""
            lastword = self.ords[lastword]
        except KeyError:
            if lastword[:-3] in self.ords_adjective:
                lastword = (
                    self.ords_adjective.get(lastword[:-3], lastword) + "соты"
                )
            elif lastword[-7:] == "дзесяць":
                lastword = "дзясяты"
            elif lastword[-9:] == "семдзесят":
                lastword = "сямідзясяты"
            elif lastword[-1] == "ь" or lastword[-2] == "ц":
                lastword = lastword[:-2] + "ты"
            elif lastword[-1] == "к":
                lastword = lastword.replace("о", "а") + "авы"

            elif lastword[-2] == "ч" or lastword[-1] == "ч":
                if lastword[-2] == "ч":
                    lastword = lastword[:-1] + "ны"
                if lastword[-1] == "ч":
                    lastword = lastword + "ны"

            elif lastword[-1] == "н" or lastword[-2] == "н":
                lastword = lastword[: lastword.rfind("н") + 1] + "ны"
            elif lastword[-3:] == "наў":
                lastword = lastword[: lastword.rfind("н") + 1] + "ны"
            elif lastword[-1] == "д" or lastword[-2] == "д":
                lastword = lastword[: lastword.rfind("д") + 1] + "ны"

        if gender == "f":
            if lastword[-2:] in [
                "ці",
            ]:
                lastword = lastword[:-2] + "цяя"
            else:
                lastword = lastword[:-1] + "ая"

        if gender == "n":
            if lastword[-2:] in ["ці", "ца"]:
                lastword = lastword[:-2] + "цяе"
            else:
                lastword = lastword[:-1] + "ае"

        outwords[-1] = self.title(lastword)
        if len(outwords) == 2 and "адна" in outwords[-2]:
            outwords[-2] = outwords[-1]
            del outwords[-1]

        if len(outwords) > 1 and (
            (any(x[0] in outwords[-1] for x in THOUSANDS.values()))
            or "тысяч" in outwords[-1]
        ):
            new_outwords = []
            for _w in outwords:
                replacement = next(
                    (x for x in TWENTIES_ORD if x[0] in _w), None
                )
                if replacement:
                    _w = _w.replace(replacement[0], replacement[1])
                new_outwords.append(_w)
            outwords = ["".join(new_outwords)]

        return " ".join(outwords).strip()

    def _money_verbose(self, number, currency):
        gender = "m"
        if currency == "UAH":
            gender = "f"

        return self._int2word(number, gender)

    def _cents_verbose(self, number, currency):
        if currency in ("UAH", "RUB", "BYN"):
            gender = "f"
        else:
            gender = "m"

        return self._int2word(number, gender)

    def _int2word(self, n, gender="m"):
        if n < 0:
            return " ".join([self.negword, self._int2word(abs(n), gender)])

        if n == 0:
            return ZERO

        words = []
        chunks = list(splitbyx(str(n), 3))
        i = len(chunks)
        for x in chunks:
            i -= 1

            if x == 0:
                continue

            n1, n2, n3 = get_digits(x)

            if n3 > 0:
                words.append(HUNDREDS[n3])

            if n2 > 1:
                words.append(TWENTIES[n2])

            if n2 == 1:
                words.append(TENS[n1])
            elif n1 > 0:
                if i == 0:
                    ones = ONES[gender]
                elif i == 1:
                    ones = ONES["f"]  # Thousands are feminine
                else:
                    ones = ONES["m"]

                words.append(ones[n1])

            if i > 0:
                words.append(self.pluralize(x, THOUSANDS[i]))

        return " ".join(words)
