import os
import re

from pytest import Item, skip

from pytest_translations.config import MARKER_NAME
from pytest_translations.utils import TranslationException

try:
    import enchant
    from enchant.tokenize import EmailFilter, HTMLChunker, URLFilter, get_tokenizer
except ImportError:
    enchant = None


def is_enchant_installed():
    return not (enchant is None)


if enchant:
    supported_languages = [name.split("_")[0] for name, _ in enchant.list_dicts()]
else:
    supported_languages = []


def word_lists():
    PWL = os.getenv("PYTEST_TRANSLATIONS_PRIVATE_WORD_LIST")

    if enchant and PWL and os.path.exists(PWL):
        return {
            fn: os.path.join(PWL, fn) for fn in os.listdir(PWL) if not os.path.isdir(fn)
        }

    else:
        return {}


class PoSpellCheckingItem(Item):
    def __init__(self, line, language, name, parent):
        self.line = line
        self.language = language

        wl = word_lists()

        private_word_list = wl.get(language, None)

        if enchant and language in supported_languages:
            self.lang_dict = enchant.DictWithPWL(language, pwl=private_word_list)
        else:
            self.lang_dict = None

        super().__init__(name, parent)
        self.add_marker(MARKER_NAME)

    def runtest(self):
        if not enchant:
            skip("enchant is not installed")

        if not self.language:
            skip("no language defined in PO file")

        if self.language not in supported_languages:
            skip("aspell dictionary for language {} not found.".format(self.language))

        text = self.line.msgstr

        # remove python format placeholders, old and new,
        # where it's a problem.
        # 1. replace everything between curly braces
        text = re.sub("{.*?}", "", text)
        # 2. remove everything between %( and )
        text = re.sub(r"\%\(.*?\)", "", text)
        # 3. remove &shy; html entity
        text = text.replace("&shy;", "")

        tokenizer = get_tokenizer(
            chunkers=[
                HTMLChunker,
            ],
            filters=(
                EmailFilter,
                URLFilter,
            ),
        )
        tokens = tokenizer(text)

        errors = [t for t, _ in tokens if not self.lang_dict.check(t)]

        if errors:
            raise TranslationException(
                "Spell checking failed: {}".format(", ".join(errors)),
                self.line.msgstr,
                [(t, self.lang_dict.suggest(t)) for t in errors],
            )

    def repr_failure(self, excinfo):
        if isinstance(excinfo.value, TranslationException):
            msg, line, wrong = excinfo.value.args
            lines = [msg, str(self.path), 'msgstr "%s"' % line]
            for i in wrong:
                lines.append("%s: %s" % i)

            return "\n".join(lines)

        else:
            return super().repr_failure(excinfo)

    def reportinfo(self):
        return (self.path, -1, "po-spelling")
