from flexmock import flexmock
from mock import patch, PropertyMock
from sportsreference import utils
from sportsreference.constants import AWAY, HOME
from sportsreference.nhl.boxscore import Boxscore


class MockField:
    def __init__(self, field):
        self._field = field

    def text(self):
        return self._field


class MockBoxscoreData:
    def __init__(self, fields):
        self._fields = fields

    def __call__(self, field):
        return self

    def items(self):
        return [self._fields]


class MockName:
    def __init__(self, name):
        self._name = name

    def text(self):
        return self._name


def mock_pyquery(url):
    class MockPQ:
        def __init__(self, html_contents):
            self.status_code = 404
            self.html_contents = html_contents
            self.text = html_contents

    boxscore = read_file('%s.html' % BOXSCORE)
    return MockPQ(boxscore)


class TestNHLBoxscore:
    @patch('requests.get', side_effect=mock_pyquery)
    def setup_method(self, *args, **kwargs):
        flexmock(Boxscore) \
            .should_receive('_parse_game_data') \
            .and_return(None)

        self.boxscore = Boxscore(None)

    def test_away_team_wins(self):
        fake_away_goals = PropertyMock(return_value=4)
        fake_home_goals = PropertyMock(return_value=3)
        type(self.boxscore)._away_goals = fake_away_goals
        type(self.boxscore)._home_goals = fake_home_goals

        assert self.boxscore.winner == AWAY

    def test_home_team_wins(self):
        fake_away_goals = PropertyMock(return_value=3)
        fake_home_goals = PropertyMock(return_value=4)
        type(self.boxscore)._away_goals = fake_away_goals
        type(self.boxscore)._home_goals = fake_home_goals

        assert self.boxscore.winner == HOME

    def test_winning_name_is_home(self):
        expected_name = 'Home Name'

        fake_winner = PropertyMock(return_value=HOME)
        fake_home_name = PropertyMock(return_value=MockName(expected_name))
        type(self.boxscore).winner = fake_winner
        type(self.boxscore)._home_name = fake_home_name

        assert self.boxscore.winning_name == expected_name

    def test_winning_name_is_away(self):
        expected_name = 'Away Name'

        fake_winner = PropertyMock(return_value=AWAY)
        fake_away_name = PropertyMock(return_value=MockName(expected_name))
        type(self.boxscore).winner = fake_winner
        type(self.boxscore)._away_name = fake_away_name

        assert self.boxscore.winning_name == expected_name

    def test_winning_abbr_is_home(self):
        expected_name = 'HOME'

        flexmock(utils) \
            .should_receive('_parse_abbreviation') \
            .and_return(expected_name)

        fake_winner = PropertyMock(return_value=HOME)
        fake_home_abbr = PropertyMock(return_value=MockName(expected_name))
        type(self.boxscore).winner = fake_winner
        type(self.boxscore)._home_abbr = fake_home_abbr

        assert self.boxscore.winning_abbr == expected_name

    def test_winning_abbr_is_away(self):
        expected_name = 'AWAY'

        flexmock(utils) \
            .should_receive('_parse_abbreviation') \
            .and_return(expected_name)

        fake_winner = PropertyMock(return_value=AWAY)
        fake_away_abbr = PropertyMock(return_value=MockName(expected_name))
        type(self.boxscore).winner = fake_winner
        type(self.boxscore)._away_abbr = fake_away_abbr

        assert self.boxscore.winning_abbr == expected_name

    def test_losing_name_is_home(self):
        expected_name = 'Home Name'

        fake_winner = PropertyMock(return_value=AWAY)
        fake_home_name = PropertyMock(return_value=MockName(expected_name))
        type(self.boxscore).winner = fake_winner
        type(self.boxscore)._home_name = fake_home_name

        assert self.boxscore.losing_name == expected_name

    def test_losing_name_is_away(self):
        expected_name = 'Away Name'

        fake_winner = PropertyMock(return_value=HOME)
        fake_away_name = PropertyMock(return_value=MockName(expected_name))
        type(self.boxscore).winner = fake_winner
        type(self.boxscore)._away_name = fake_away_name

        assert self.boxscore.losing_name == expected_name

    def test_losing_abbr_is_home(self):
        expected_name = 'HOME'

        flexmock(utils) \
            .should_receive('_parse_abbreviation') \
            .and_return(expected_name)

        fake_winner = PropertyMock(return_value=AWAY)
        fake_home_abbr = PropertyMock(return_value=MockName(expected_name))
        type(self.boxscore).winner = fake_winner
        type(self.boxscore)._home_abbr = fake_home_abbr

        assert self.boxscore.losing_abbr == expected_name

    def test_losing_abbr_is_away(self):
        expected_name = 'AWAY'

        flexmock(utils) \
            .should_receive('_parse_abbreviation') \
            .and_return(expected_name)

        fake_winner = PropertyMock(return_value=HOME)
        fake_away_abbr = PropertyMock(return_value=MockName(expected_name))
        type(self.boxscore).winner = fake_winner
        type(self.boxscore)._away_abbr = fake_away_abbr

        assert self.boxscore.losing_abbr == expected_name

    def test_invalid_away_game_winning_goals_returns_default(self):
        goals = ['0', '1', 'bad']

        fake_goals = PropertyMock(return_value=goals)
        fake_num_skaters = PropertyMock(return_value=3)
        fake_num_goalies = PropertyMock(return_value=0)
        type(self.boxscore)._away_game_winning_goals = fake_goals
        type(self.boxscore)._away_skaters = fake_num_skaters
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_game_winning_goals == 1

    def test_invalid_away_even_strength_assists_returns_default(self):
        assists = ['0', '1', 'bad']

        fake_assists = PropertyMock(return_value=assists)
        fake_num_skaters = PropertyMock(return_value=3)
        fake_num_goalies = PropertyMock(return_value=0)
        type(self.boxscore)._away_even_strength_assists = fake_assists
        type(self.boxscore)._away_skaters = fake_num_skaters
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_even_strength_assists == 1

    def test_invalid_home_even_strength_assists_returns_default(self):
        assists = ['0', '1', 'bad']

        fake_assists = PropertyMock(return_value=assists)
        fake_num_skaters = PropertyMock(return_value=0)
        fake_num_goalies = PropertyMock(return_value=0)
        type(self.boxscore)._home_even_strength_assists = fake_assists
        type(self.boxscore)._away_skaters = fake_num_skaters
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.home_even_strength_assists == 1

    def test_invalid_away_power_play_assists_returns_default(self):
        assists = ['0', '1', 'bad']

        fake_assists = PropertyMock(return_value=assists)
        fake_num_skaters = PropertyMock(return_value=3)
        fake_num_goalies = PropertyMock(return_value=0)
        type(self.boxscore)._away_power_play_assists = fake_assists
        type(self.boxscore)._away_skaters = fake_num_skaters
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_power_play_assists == 1

    def test_invalid_home_power_play_assits_returns_default(self):
        assists = ['0', '1', 'bad']

        fake_assists = PropertyMock(return_value=assists)
        fake_num_skaters = PropertyMock(return_value=0)
        fake_num_goalies = PropertyMock(return_value=0)
        type(self.boxscore)._home_power_play_assists = fake_assists
        type(self.boxscore)._away_skaters = fake_num_skaters
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.home_power_play_assists == 1

    def test_invalid_away_short_handed_assists_returns_default(self):
        assists = ['0', '1', 'bad']

        fake_assists = PropertyMock(return_value=assists)
        fake_num_skaters = PropertyMock(return_value=3)
        fake_num_goalies = PropertyMock(return_value=0)
        type(self.boxscore)._away_short_handed_assists = fake_assists
        type(self.boxscore)._away_skaters = fake_num_skaters
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_short_handed_assists == 1

    def test_invalid_home_short_handed_assits_returns_default(self):
        assists = ['0', '1', 'bad']

        fake_assists = PropertyMock(return_value=assists)
        fake_num_skaters = PropertyMock(return_value=0)
        fake_num_goalies = PropertyMock(return_value=0)
        type(self.boxscore)._home_short_handed_assists = fake_assists
        type(self.boxscore)._away_skaters = fake_num_skaters
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.home_short_handed_assists == 1

    def test_invalid_url_returns_none(self):
        result = Boxscore(None)._retrieve_html_page('')

        assert result is None

    def test_regular_season_information(self):
        fields = {
            'date': 'October 5, 2017',
            'playoff_round': None,
            'time': '7:00 PM',
            'attendance': 17565,
            'arena': 'TD Garden',
            'duration': '2:39'
        }

        mock_field = """October 5, 2017, 7:00 PM
Attendance: 17,565
Arena: TD Garden
Game Duration: 2:39
Logos via Sports Logos.net / About logos
"""

        m = MockBoxscoreData(MockField(mock_field))

        self.boxscore._parse_game_date_and_location(m)
        for field, value in fields.items():
            assert getattr(self.boxscore, field) == value

    def test_playoffs_information(self):
        fields = {
            'date': 'June 7, 2018',
            'playoff_round': 'Stanley Cup Final',
            'time': '8:00 PM',
            'attendance': 18529,
            'arena': 'T-Mobile Arena',
            'duration': '2:45'
        }

        mock_field = """June 7, 2018, 8:00 PM
Stanley Cup Final
Attendance: 18,529
Arena: T-Mobile Arena
Game Duration: 2:45
Logos via Sports Logos.net / About logos
"""

        m = MockBoxscoreData(MockField(mock_field))

        self.boxscore._parse_game_date_and_location(m)
        for field, value in fields.items():
            assert getattr(self.boxscore, field) == value

    def test_no_game_information(self):
        fields = {
            'date': '',
            'playoff_round': None,
            'time': None,
            'attendance': None,
            'arena': None,
            'duration': None
        }

        mock_field = '\n'

        m = MockBoxscoreData(MockField(mock_field))

        self.boxscore._parse_game_date_and_location(m)
        for field, value in fields.items():
            assert getattr(self.boxscore, field) == value

    def test_limited_game_information(self):
        fields = {
            'date': 'June 7, 2018',
            'playoff_round': 'Stanley Cup Final',
            'time': None,
            'attendance': None,
            'arena': 'T-Mobile Arena',
            'duration': None
        }

        mock_field = """June 7, 2018
Stanley Cup Final
Arena: T-Mobile Arena
Logos via Sports Logos.net / About logos
"""

        m = MockBoxscoreData(MockField(mock_field))

        self.boxscore._parse_game_date_and_location(m)
        for field, value in fields.items():
            assert getattr(self.boxscore, field) == value

    def test_away_shutout_single_goalies(self):
        shutout = ['1', '0']

        fake_shutout = PropertyMock(return_value=shutout)
        fake_num_goalies = PropertyMock(return_value=1)
        type(self.boxscore)._away_shutout = fake_shutout
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_shutout == 1

    def test_away_shutout_multiple_goalies(self):
        shutout = ['0', '1', '0']

        fake_shutout = PropertyMock(return_value=shutout)
        fake_num_goalies = PropertyMock(return_value=2)
        type(self.boxscore)._away_shutout = fake_shutout
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_shutout == 1

    def test_away_shutout_multiple_goalies_empty_field(self):
        shutout = ['', '1', '0']

        fake_shutout = PropertyMock(return_value=shutout)
        fake_num_goalies = PropertyMock(return_value=2)
        type(self.boxscore)._away_shutout = fake_shutout
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_shutout == 1

    def test_home_shutout_single_goalies(self):
        shutout = ['0', '1']

        fake_shutout = PropertyMock(return_value=shutout)
        fake_num_goalies = PropertyMock(return_value=1)
        type(self.boxscore)._home_shutout = fake_shutout
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.home_shutout == 1

    def test_home_shutout_multiple_goalies(self):
        shutout = ['0', '0', '1']

        fake_shutout = PropertyMock(return_value=shutout)
        fake_num_goalies = PropertyMock(return_value=1)
        type(self.boxscore)._home_shutout = fake_shutout
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.home_shutout == 1

    def test_home_shutout_multiple_goalies_empty_field(self):
        shutout = ['0', '', '1']

        fake_shutout = PropertyMock(return_value=shutout)
        fake_num_goalies = PropertyMock(return_value=1)
        type(self.boxscore)._home_shutout = fake_shutout
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.home_shutout == 1

    def test_away_saves_single_goalies(self):
        saves = ['29', '30']

        fake_saves = PropertyMock(return_value=saves)
        fake_num_goalies = PropertyMock(return_value=1)
        type(self.boxscore)._away_saves = fake_saves
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_saves == 29

    def test_away_saves_multiple_goalies_empty_field(self):
        saves = ['29', '3', '30']

        fake_saves = PropertyMock(return_value=saves)
        fake_num_goalies = PropertyMock(return_value=2)
        type(self.boxscore)._away_saves = fake_saves
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_saves == 32

    def test_away_saves_multiple_goalies_empty_field(self):
        saves = ['29', '', '30']

        fake_saves = PropertyMock(return_value=saves)
        fake_num_goalies = PropertyMock(return_value=2)
        type(self.boxscore)._away_saves = fake_saves
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.away_saves == 29

    def test_home_saves_single_goalies(self):
        saves = ['29', '30']

        fake_saves = PropertyMock(return_value=saves)
        fake_num_goalies = PropertyMock(return_value=1)
        type(self.boxscore)._home_saves = fake_saves
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.home_saves == 30

    def test_home_saves_multiple_goalies_empty_field(self):
        saves = ['29', '3', '30']

        fake_saves = PropertyMock(return_value=saves)
        fake_num_goalies = PropertyMock(return_value=1)
        type(self.boxscore)._home_saves = fake_saves
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.home_saves == 33

    def test_home_saves_multiple_goalies_empty_field(self):
        saves = ['29', '30', '']

        fake_saves = PropertyMock(return_value=saves)
        fake_num_goalies = PropertyMock(return_value=1)
        type(self.boxscore)._home_saves = fake_saves
        type(self.boxscore)._away_goalies = fake_num_goalies

        assert self.boxscore.home_saves == 30

    def test_away_save_percentage(self):
        fake_saves = PropertyMock(return_value=30)
        fake_shots_on_goal = PropertyMock(return_value=33)
        type(self.boxscore).away_saves = fake_saves
        type(self.boxscore).home_shots_on_goal = fake_shots_on_goal

        assert self.boxscore.away_save_percentage == 0.909

    def test_away_save_percentage_zero_shots(self):
        fake_saves = PropertyMock(return_value=0)
        fake_shots_on_goal = PropertyMock(return_value=0)
        type(self.boxscore).away_saves = fake_saves
        type(self.boxscore).home_shots_on_goal = fake_shots_on_goal

        assert self.boxscore.away_save_percentage == 0.0

    def test_home_save_percentage(self):
        fake_saves = PropertyMock(return_value=30)
        fake_shots_on_goal = PropertyMock(return_value=33)
        type(self.boxscore).home_saves = fake_saves
        type(self.boxscore).away_shots_on_goal = fake_shots_on_goal

        assert self.boxscore.home_save_percentage == 0.909

    def test_home_save_percentage_zero_shots(self):
        fake_saves = PropertyMock(return_value=0)
        fake_shots_on_goal = PropertyMock(return_value=0)
        type(self.boxscore).home_saves = fake_saves
        type(self.boxscore).away_shots_on_goal = fake_shots_on_goal

        assert self.boxscore.home_save_percentage == 0.0

    def test_no_class_information_returns_dataframe_of_none(self):
        mock_goals = PropertyMock(return_value=None)
        type(self.boxscore)._away_goals = mock_goals
        type(self.boxscore)._home_goals = mock_goals

        assert self.boxscore.dataframe is None
