import pytest
from itertools import product
from urllib.parse import parse_qs, urlparse

from src.battlenet_client.utils.constants import Region
from src.battlenet_client.apis import oauth
from src.battlenet_client.utils.exceptions import BNetRegionNotFoundError

from tests.constants import INVALID_REGIONS

@pytest.mark.parametrize('region_tag', Region.VALID_REGIONS)
def test_authorization_url(region_tag):
    result = oauth.authorization_url(region_tag, 'CLIENTID', 'HTTPS://REDIRECT', 'NoneScope',
                                     'NONCE', 'code')
    assert isinstance(result, str)
    assert result.rfind("client_id") != -1
    assert result.rfind("redirect_uri") != -1
    assert result.rfind("scope") != -1
    assert result.rfind("state") != -1
    assert result.rfind("response_type") != -1
    assert result.rfind("CLIENTID") != -1
    assert result.rfind("HTTPS%3A%2F%2FREDIRECT") != -1
    assert result.rfind("NoneScope") != -1
    assert result.rfind("NONCE") != -1
    assert result.rfind("code") != -1
    if region_tag == 'cn':
        assert result.startswith('https://oauth.battlenet.com.cn/authorize')
    else:
        assert result.startswith('https://oauth.battle.net/authorize')

    query_parms = parse_qs(urlparse(result).query)
    assert "client_id" in query_parms.keys()
    assert "redirect_uri" in query_parms.keys()
    assert "scope" in query_parms.keys()
    assert "state" in query_parms.keys()
    assert "response_type" in query_parms.keys()
    assert "CLIENTID" in query_parms['client_id']
    assert "HTTPS://REDIRECT" in query_parms['redirect_uri']
    assert "NoneScope" in query_parms['scope']
    assert "NONCE" in query_parms['state']
    assert "code" in query_parms['response_type']


@pytest.mark.parametrize('region_tag', INVALID_REGIONS)
def test_authorization_url_invalid_region(region_tag):
    with pytest.raises(BNetRegionNotFoundError):
        oauth.authorization_url(region_tag, 'CLIENTID', 'HTTPS://REDIRECT', 'NoneScope',
                                'NONCE', 'code')


@pytest.mark.parametrize('region_tag, grant_type', list(product(Region.VALID_REGIONS, ("client_credentials",))))
def test_fetch_token_client_credential(region_tag, grant_type):
    result = oauth.fetch_token(region_tag, grant_type)
    assert isinstance(result, tuple)
    assert len(result) == 4
    assert isinstance(result[0], str)
    assert result[1] is None
    assert result[2] is None
    assert isinstance(result[3], dict)

    if region_tag == 'cn':
        assert result[0].startswith('https://oauth.battlenet.com.cn/token')
    else:
        assert result[0].startswith('https://oauth.battle.net/token')

    assert 'grant_type' in result[3].keys()
    assert 'code' in result[3].keys()
    assert 'redirect_uri' in result[3].keys()
    assert result[3]['grant_type'] == 'client_credentials'
    assert result[3]['grant_type'] == grant_type



@pytest.mark.parametrize('region_tag', Region.VALID_REGIONS)
def test_user_info(region_tag):

    data = oauth.user_info(region_tag)
    assert isinstance(data, tuple)
    assert isinstance(data[0], str)
    assert data[1] is None
    assert data[2] is None
    assert data[3] is None
    if region_tag == 'cn':
        assert data[0] == "https://oauth.battlenet.com.cn/userinfo"
    else:
        assert data[0] == 'https://oauth.battle.net/userinfo'



@pytest.mark.parametrize('region_tag', INVALID_REGIONS)
def test_user_info_invalid_region(region_tag):
    with pytest.raises(BNetRegionNotFoundError):
        oauth.user_info(region_tag)


@pytest.mark.parametrize('region_tag', Region.VALID_REGIONS)
def test_token_validation(region_tag):
    token = 'my_good_token_1234'
    data = oauth.token_validation(region_tag, token)
    assert isinstance(data, tuple)
    assert isinstance(data[0], str)
    assert data[1] is None
    assert data[2] is None
    assert isinstance(data[3], dict)
    if region_tag == 'cn':
        assert data[0] == "https://oauth.battlenet.com.cn/check_token"
    else:
        assert data[0] == 'https://oauth.battle.net/check_token'
    assert data[1] is None
    assert 'token' in data[3].keys()
    assert token == data[3]["token"]


@pytest.mark.parametrize('region_tag', INVALID_REGIONS)
def test_token_validation_invalid_region(region_tag):
    with pytest.raises(BNetRegionNotFoundError):
        token = 'my_good_token_1234'
        oauth.token_validation(region_tag, token)
