import pytest

from mwtp.exceptions import (
	TitleContainsHTMLEntity, TitleContainsIllegalCharacter, TitleContainsSignatureComponent,
	TitleContainsURLEncodedCharacter, TitleHasRelativePathComponent, TitleHasSecondLevelNamespace, TitleIsBlank,
	TitleIsTooLong, TitleStartsWithColon
)
from mwtp.title import Title


@pytest.fixture(scope = 'module')
def parser(en_wikipedia_parser):
	yield en_wikipedia_parser


@pytest.mark.parametrize('string, expected', [
	### Plain
	('Foobar', 'Foobar'),
	('.com', '.com'),
	
	### With fragments
	('Foo#bar', 'Foo'),
	('Talk:  fOo # bar', 'Talk:FOo'),
	('Foo   #  __  bar  __ ', 'Foo'),
	('Foo&#23;bar', 'Foo&'),
	('pRoJecT _:_ foo&#123;bar', 'Wikipedia:Foo&'),
	
	### Quotes
	('Foo "bar"', 'Foo "bar"'),
	("Foo 'Bar'", "Foo 'Bar'"),
	('"', '"'),
	("'", "'"),
	
	### Tildes
	('~', '~'),
	('~~', '~~'),
	('Foo~~', 'Foo~~'),
	
	### With namespace prefixes
	('Talk:Foobar', 'Talk:Foobar'),
	('TaLk_:_Foo _: Bar', 'Talk:Foo : Bar'),
	('fiLe _:__ Foo _.svg', 'File:Foo .svg'),
	('FilE__ __talk:bAr.svg', 'File talk:BAr.svg'),
	
	### Barely relative path components
	('.../Foobar', '.../Foobar'),
	('Foo/.../Bar', 'Foo/.../Bar'),
	('Foobar/...', 'Foobar/...'),
	
	### Single leading colon
	(':Foobar', 'Foobar'),
	('___:_ __ __fOoBar', 'FOoBar'),
	
	### Length
	(f'catEgOry  _:_ {"W" * 255}', f'Category:{"W" * 255}'),
	('W' * 255, 'W' * 255),
	(f'File :___{"W" * 232}.jpeg', f'File:{"W" * 232}.jpeg'),
	
	### Case-sensitive
	('Gadget:foo', 'Gadget:foo'),
	('gAdget  _ :_ _ fOo', 'Gadget:fOo'),
	
	### Unicode uppercase
	('ß is ss', 'ß is ss'),
	('ᾇ', 'ᾏ'),
	
	### Unipain
	('\ud81b\ude7ffoo', '\ud81b\ude7ffoo'),
	('𖹿foo', '𖹿foo')
])
def test_parse_valid_title(parser, string, expected):
	title = parser.parse(string)
	
	assert isinstance(title, Title)
	assert title.full_name == expected


@pytest.mark.parametrize('string', [
	'', ':', '__  __', '  __  ',
	'Talk:', 'Category: ', 'Category: #bar'
])
def test_parse_blank_title(parser, string):
	with pytest.raises(TitleIsBlank):
		parser.parse(string)


@pytest.mark.parametrize('string', [
	'A [ B', 'A ] B', 'A { B', 'A } B', 'A < B', 'A > B',
	'A | B', 'A \t B', 'A \n B',
	'Foo\uFFFDbar'
])
def test_parse_illegal_character(parser, string):
	with pytest.raises(TitleContainsIllegalCharacter):
		parser.parse(string)


@pytest.mark.parametrize('string', [
	'Foo%20bar', 'Foo%23bar', 'Foo%2523bar'
])
def test_parse_url_encoded_character(parser, string):
	with pytest.raises(TitleContainsURLEncodedCharacter):
		parser.parse(string)


@pytest.mark.parametrize('string', [
	'Foo&eacute;bar', 'Foo&nbsp;bar',
	'Foo&nonexistententity;bar'
])
def test_parse_html_entity(parser, string):
	with pytest.raises(TitleContainsHTMLEntity):
		parser.parse(string)


@pytest.mark.parametrize('string', [
	'Talk:Category:Foobar',
	'Talk:File:Foobar.svg',
	'_ TaLk_: tAlK: Fooboo',
	' _ TALk: ___ project: foo'
])
def test_parse_second_level_namespace(parser, string):
	with pytest.raises(TitleHasSecondLevelNamespace):
		parser.parse(string)


@pytest.mark.parametrize('string', [
	'.', '..',
	'./Foobar', '../Foobar',
	'Foo/./Bar', 'Foo/../Bar',
	'Foobar/.', 'Foobar/..'
])
def test_parse_relative_path_component(parser, string):
	with pytest.raises(TitleHasRelativePathComponent):
		parser.parse(string)


@pytest.mark.parametrize('string', [
	'Username ~~~',
	'Signature ~~~~',
	'Timestamp ~~~~~'
])
def test_parse_signature_component(parser, string):
	with pytest.raises(TitleContainsSignatureComponent):
		parser.parse(string)


@pytest.mark.parametrize('string', [
	'::Foo',
	': _:_Bar',
	'Talk: : Foobar',
	'Project___:: Foobar'
])
def test_parse_leading_colon(parser, string):
	with pytest.raises(TitleStartsWithColon):
		parser.parse(string)


@pytest.mark.parametrize('string', [
	'w' * 256,
	'À' * 128,
	'维' * 85 + 'k',
	'w' * 252 + '.jpeg',
	'À' * 126 + '.jpeg',
	'维' * 85 + '.jpeg'
])
def test_parse_lengthy_page_name(parser, string):
	with pytest.raises(TitleIsTooLong):
		parser.parse(string)
