import unicodedata

import pytest

import remedapy as R


class TestCopiedFromTypeFest:
    @pytest.mark.parametrize(
        ['input', 'expected'],
        [
            ('', []),
            ('a', ['a']),
            ('B', ['B']),
            ('aa', ['aa']),
            ('aB', ['a', 'B']),
            ('Ba', ['Ba']),
            ('BB', ['BB']),
            ('aaa', ['aaa']),
            ('aaB', ['aa', 'B']),
            ('aBa', ['a', 'Ba']),
            ('aBB', ['a', 'BB']),
            ('Baa', ['Baa']),
            ('BaB', ['Ba', 'B']),
            ('BBa', ['B', 'Ba']),
            ('BBB', ['BBB']),
            ('aaaa', ['aaaa']),
            ('aaaB', ['aaa', 'B']),
            ('aaBa', ['aa', 'Ba']),
            ('aaBB', ['aa', 'BB']),
            ('aBaa', ['a', 'Baa']),
            ('aBaB', ['a', 'Ba', 'B']),
            ('aBBa', ['a', 'B', 'Ba']),
            ('aBBB', ['a', 'BBB']),
            ('Baaa', ['Baaa']),
            ('BaaB', ['Baa', 'B']),
            ('BaBa', ['Ba', 'Ba']),
            ('BaBB', ['Ba', 'BB']),
            ('BBaa', ['B', 'Baa']),
            ('BBaB', ['B', 'Ba', 'B']),
            ('BBBa', ['BB', 'Ba']),
            ('BBBB', ['BBBB']),
            ('aaaaa', ['aaaaa']),
            ('aaaaB', ['aaaa', 'B']),
            ('aaaBa', ['aaa', 'Ba']),
            ('aaaBB', ['aaa', 'BB']),
            ('aaBaa', ['aa', 'Baa']),
            ('aaBaB', ['aa', 'Ba', 'B']),
            ('aaBBa', ['aa', 'B', 'Ba']),
            ('aaBBB', ['aa', 'BBB']),
            ('aBaaa', ['a', 'Baaa']),
            ('aBaaB', ['a', 'Baa', 'B']),
            ('aBaBa', ['a', 'Ba', 'Ba']),
            ('aBaBB', ['a', 'Ba', 'BB']),
            ('aBBaa', ['a', 'B', 'Baa']),
            ('aBBaB', ['a', 'B', 'Ba', 'B']),
            ('aBBBa', ['a', 'BB', 'Ba']),
            ('aBBBB', ['a', 'BBBB']),
            ('Baaaa', ['Baaaa']),
            ('BaaaB', ['Baaa', 'B']),
            ('BaaBa', ['Baa', 'Ba']),
            ('BaaBB', ['Baa', 'BB']),
            ('BaBaa', ['Ba', 'Baa']),
            ('BaBaB', ['Ba', 'Ba', 'B']),
            ('BaBBa', ['Ba', 'B', 'Ba']),
            ('BaBBB', ['Ba', 'BBB']),
            ('BBaaa', ['B', 'Baaa']),
            ('BBaaB', ['B', 'Baa', 'B']),
            ('BBaBa', ['B', 'Ba', 'Ba']),
            ('BBaBB', ['B', 'Ba', 'BB']),
            ('BBBaa', ['BB', 'Baa']),
            ('BBBaB', ['BB', 'Ba', 'B']),
            ('BBBBa', ['BBB', 'Ba']),
            ('BBBBB', ['BBBBB']),
        ],
    )
    def test_case_changes(self, input: str, expected: list[str]):
        assert R.to_words(input) == expected

    @pytest.mark.parametrize(
        ['input', 'expected'],
        [
            ('hello world', ['hello', 'world']),
            ('Hello-world', ['Hello', 'world']),
            ('hello_world', ['hello', 'world']),
            ('hello  world', ['hello', 'world']),
            ('Hello--world', ['Hello', 'world']),
            ('hello__world', ['hello', 'world']),
            ('   hello  world', ['hello', 'world']),
            ('---Hello--world', ['Hello', 'world']),
            ('___hello__world', ['hello', 'world']),
            ('hello  world   ', ['hello', 'world']),
            ('hello\tworld', ['hello', 'world']),
            ('Hello--world--', ['Hello', 'world']),
            ('hello__world___', ['hello', 'world']),
            ('___ hello -__  _world', ['hello', 'world']),
            ('__HelloWorld-HELLOWorld helloWORLD', ['Hello', 'World', 'HELLO', 'World', 'hello', 'WORLD']),
            ('hello WORLD lowercase', ['hello', 'WORLD', 'lowercase']),
            ('hello WORLD-lowercase', ['hello', 'WORLD', 'lowercase']),
            ('hello WORLD Uppercase', ['hello', 'WORLD', 'Uppercase']),
        ],
    )
    def test_whitespaces(self, input: str, expected: list[str]):
        assert R.to_words(input) == expected

    @pytest.mark.parametrize(
        ['input', 'expected'],
        [
            ('item0', ['item', '0']),
            ('item01', ['item', '01']),
            ('item10', ['item', '10']),
            ('item010', ['item', '010']),
            ('0item0', ['0', 'item', '0']),
            ('01item01', ['01', 'item', '01']),
            ('10item10', ['10', 'item', '10']),
            ('010item010', ['010', 'item', '010']),
            ('item0_item_1 item -2', ['item', '0', 'item', '1', 'item', '2']),
        ],
    )
    def test_digits(self, input: str, expected: list[str]):
        assert R.to_words(input) == expected

    def test_doesnt_break_on_accented_characters(self):
        assert R.to_words('naïveApproach') == ['naïve', 'Approach']
        assert R.to_words('résumé-data') == ['résumé', 'data']

    def test_doesnt_split_at_case_boundaries_with_accented_characters(self):
        assert R.to_words('caféWorld') == ['caféWorld']

    @pytest.mark.parametrize(
        ['normalisation'],
        [
            ('NFC',),
            ('NFD',),
            ('NFKC',),
            ('NFKD',),
        ],
    )
    def test_normalization_doesnt_matter(self, normalisation: 'unicodedata._NormalizationForm'):  # pyright: ignore[reportPrivateUsage]
        data = 'caféWorld'
        normalized = unicodedata.normalize(normalisation, data)
        assert R.to_words(normalized) == [normalized]

    def test_treats_mixed_scripts_as_single_words(self):
        assert R.to_words('helloМосква') == ['helloМосква']
        assert R.to_words('dataΕλλάδα') == ['dataΕλλάδα']

    def test_handles_contractions_and_possessives(self):
        assert R.to_words("can'tStop") == ["can't", 'Stop']
        assert R.to_words("user's-data") == ["user's", 'data']

    def test_handles_curly_apostrophes(self):
        assert R.to_words("user'sData") == ["user's", 'Data']
        assert R.to_words('user\u2019sData') == ['user\u2019s', 'Data']

    def test_treats_emojis_as_part_of_words(self):
        assert R.to_words('hello🎉World') == ['hello🎉World']

    def test_treats_special_unicode_as_part_of_words(self):
        assert R.to_words('data𝒽ello') == ['data𝒽ello']

    def test_preserves_combining_diacritical_marks(self):
        assert R.to_words('cafe\u0301World') == ['cafe\u0301World']
