# coding=utf-8
"""
run the test from the src/invesytoolbox directory:
pytest ../tests/test_text_name.py -v
"""
import json
import random
from pathlib import Path

from invesytoolbox.itb_text_name import (
    adjust_spaces_on_punctuation,
    and_list,
    capitalize_name,
    could_be_a_name,
    get_gender,
    leet,
    map_special_chars,
    normalize_name,
    normalize_text,
    sort_names,
    sort_word_list,
)

TESTDATA = Path(__file__).parent / 'testdata'
with open(TESTDATA / 'text_name.json') as f:
    _data = json.load(f)

reference_names = _data['reference_names']
reference_names_sorted = _data['reference_names_sorted']
lower_text = _data['lower_text']
punct_texts = _data['punct_texts']
punct_texts_corrected = _data['punct_texts_corrected']
sort_word_lists = _data['sort_word_lists']
and_list_tests = _data['and_list_tests']


def test_adjust_spaces_on_punctuation():
    for lang, text in punct_texts.items():
        corrected_text = adjust_spaces_on_punctuation(
            text=text,
            language=lang
        )
        assert corrected_text == punct_texts_corrected[lang]


def test_and_list():
    for test in and_list_tests:
        and_str = and_list(test['input'])
        assert and_str == test['expected']


def test_leet():
    random.seed(42)

    # basic: result is a non-empty string
    result = leet('Hello World')
    assert isinstance(result, str)
    assert len(result) > 0

    # max_length is respected
    result = leet('Hello World', max_length=5)
    assert len(result) <= 5

    result = leet('Hello World', max_length=5, start_at_begin=False)
    assert len(result) <= 5

    # empty input gives empty output
    assert leet('') == ''


def test_capitalize_name():
    for name_dict in reference_names.values():
        capitalized_name = capitalize_name(
            text=name_dict.get('lowercase')
        )
        assert name_dict.get('capitalized') == capitalized_name


def test_get_gender():
    for name, name_dict in reference_names.items():
        correct_gender = name_dict.get('gender')
        gender = get_gender(name.split()[0])  # prename

        try:
            assert gender == correct_gender
        except AssertionError:
            msg = f'{gender} != {correct_gender} for {name}'
            raise AssertionError(msg)


def test_map_special_chars():
    for name, name_dict in reference_names.items():
        correct_ascii = name_dict.get('ascii')
        ascii_str = map_special_chars(text=name)

        try:
            assert ascii_str == correct_ascii
        except AssertionError:
            msg = f'ASCII: {ascii_str} != {correct_ascii} for {name}'
            raise AssertionError(msg)


def test_map_special_chars_sort():
    for name, name_dict in reference_names.items():
        correct_sort = name_dict.get('sort')
        sort_str = map_special_chars(text=name, sort=True)

        try:
            assert sort_str == correct_sort
        except AssertionError:
            msg = f'SORT: {sort_str} != {correct_sort} for {name}'
            raise AssertionError(msg)


def test_normalize_name():
    for name, name_dict in reference_names.items():
        normalized_name = normalize_name(
            name=name,
            lastname=name_dict['lastname']
        )
        assert name == normalized_name

        name_data = normalize_name(
            name=name,
            lastname=name_dict['lastname'],
            returning='dict'
        )
        assert name_dict.get('human_name') == name_data


def test_sort_names():
    names_list = list(reference_names)
    sorted_names = sort_names(names=names_list)

    assert sorted_names == reference_names_sorted


def test_normalize_text():
    # two-character unicode ä (a + combining diaeresis) should become single-char ä
    text_with_combining = 'a\u0308' 'o\u0308' 'u\u0308'  # ä ö ü via combining chars
    result = normalize_text(text_with_combining)
    assert result == 'äöü'

    # uppercase variants
    text_upper = 'A\u0308' 'O\u0308' 'U\u0308'
    result = normalize_text(text_upper)
    assert result == 'ÄÖÜ'

    # text without special chars should pass through unchanged
    assert normalize_text('hello world') == 'hello world'

    # mixed text
    result = normalize_text('Gru\u0308n und Blo\u0308d')
    assert result == 'Grün und Blöd'


def test_sort_word_list():
    for test_case in sort_word_lists:
        result = sort_word_list(test_case['input'])
        assert result == test_case['expected']


def test_could_be_a_name():
    for name, vals in reference_names.items():
        kwargs = {'name': name}

        if ' ' not in name:
            kwargs['prename'] = True

        assert could_be_a_name(**kwargs) == vals.get('is_a_name'), f'could_be_a_name failed on {name}'
