import asyncio
import codecs
import os.path as path
import pytest
import re

import fizzbotz


def get_test_file(filename, extension):
    file_path = path.join(path.dirname(__file__), 'test_files', '{}.{}'.
                          format(filename, extension))
    with codecs.open(file_path, 'r', 'utf-8') as test_file:
        return test_file.read()[:-1]  # strip \n from end of file


@pytest.mark.asyncio
@pytest.mark.parametrize('filename, message_function', [
                        ('bestoftwitchchat', fizzbotz.TwitchChat().
                         get_bestoftwitchchat_pasta),
                        ('twitchquotes', fizzbotz.TwitchChat().
                         get_twitchquotes_pasta),
                        ('twitchquotes_emotes', fizzbotz.TwitchChat().
                         get_twitchquotes_pasta),
                        ('twitchquotes_text_art', fizzbotz.TwitchChat().
                         get_twitchquotes_pasta),
                        ('twitchquotes_unicode', fizzbotz.TwitchChat().
                         get_twitchquotes_pasta),
                        ('joke_oneliner', fizzbotz.Joke().
                         get_oneliner),
                        ('joke_oneliner_quote', fizzbotz.Joke().
                         get_oneliner),
                        ('insult', fizzbotz.Insult().get)
])
@asyncio.coroutine
def test_messages(filename, message_function):
    raw_html = get_test_file(filename, 'html')
    message = yield from message_function(from_html=raw_html)

    expected_message = get_test_file(filename, 'txt')
    if message != expected_message:
        pytest.fail("Didn't get expected result.\n\n"
                    ""
                    "Expected:\n"
                    "{}\n\n"
                    ""
                    "Received:\n"
                    "{}".format(expected_message, message))


@pytest.mark.asyncio
@asyncio.coroutine
def test_imgur():
    pattern = re.compile('https://i.imgur.com/\w{5}.png')
    result = yield from fizzbotz.Imgur().get()

    assert pattern.match(result)


@pytest.mark.asyncio
@asyncio.coroutine
def test_square():
    square_message = yield from fizzbotz.Square().get('ggsnipes/sgak')
    assert square_message == "```\n" \
                             "G G S N I P E S / S G A K\n" \
                             "G S N I P E S / S G A K A\n" \
                             "S N I P E S / S G A K A G\n" \
                             "N I P E S / S G A K A G S\n" \
                             "I P E S / S G A K A G S /\n" \
                             "P E S / S G A K A G S / S\n" \
                             "E S / S G A K A G S / S E\n" \
                             "S / S G A K A G S / S E P\n" \
                             "/ S G A K A G S / S E P I\n" \
                             "S G A K A G S / S E P I N\n" \
                             "G A K A G S / S E P I N S\n" \
                             "A K A G S / S E P I N S G\n" \
                             "K A G S / S E P I N S G G\n" \
                             "```"


@pytest.mark.asyncio
@pytest.mark.parametrize('string_literal, exception', [
                        ('',
                         fizzbotz.EmptyStringError),
                        ('This string is longer than the max allowed.',
                         fizzbotz.StringLengthError)
])
@asyncio.coroutine
def test_square_exceptions(string_literal, exception):
    with pytest.raises(exception):
        yield from fizzbotz.Square().get(string_literal)


@pytest.mark.asyncio
@pytest.mark.parametrize('dice', ['2d6', '2D6', '5d999', '999d5', '12', ''])
@asyncio.coroutine
def test_roll(dice):
    result = yield from fizzbotz.Roll().get(dice)
    assert result is not None


@pytest.mark.asyncio
@pytest.mark.parametrize('dice', ['d99999', '99999d', '1d1', '1', 'foo',
                                  '-999d-999', '999d-999'])
@asyncio.coroutine
def test_roll_exception(dice):
    with pytest.raises(ValueError):
        yield from fizzbotz.Roll().get(dice)


@pytest.mark.asyncio
@asyncio.coroutine
def test_roll_length():
    with pytest.raises(fizzbotz.StringLengthError):
        yield from fizzbotz.Roll().get('99999999999999999999999d9')
