import logging
import requests
from unittest.mock import patch

import pytest

from common import urls

logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s:  %(message)s',
    level=logging.DEBUG)

# This avoids needing the internet for testing.
urls.tldextract.extract = urls.tldextract.TLDExtract(suffix_list_urls=None)


@pytest.fixture
def clear_tls_cache():
    urls._test_domain_for_tls_support.cache_clear()


@pytest.fixture
def clear_rewriter_cache():
    urls.rewrite_redirected_url.cache_clear()


@pytest.fixture
def get_good(monkeypatch):
    def mock_get(url, timeout=60):
        return requests.Response()
    monkeypatch.setattr(urls.requests, 'get', mock_get)


@pytest.fixture
def get_bad(monkeypatch):
    def mock_get(url, timeout=60):
        raise Exception
    monkeypatch.setattr(urls.requests, 'get', mock_get)


def test_validate_url_string_adds_http_without_scheme(
        clear_tls_cache, get_bad
):
    url_string = 'creativecomons.org'
    actual_validated_url = urls.validate_url_string(url_string)
    expect_validated_url = 'http://creativecomons.org'
    assert actual_validated_url == expect_validated_url


def test_validate_url_string_nones_with_invalid_structure_domain(
        clear_tls_cache, get_bad
):
    url_string = 'https:/abcd'
    actual_validated_url = urls.validate_url_string(url_string)
    assert actual_validated_url is None


def test_validate_url_string_upgrades_scheme(clear_tls_cache, get_good):
    url_string = 'http://abcd.com'
    actual_validated_url = urls.validate_url_string(url_string)
    expect_validated_url = 'https://abcd.com'
    assert actual_validated_url == expect_validated_url


def test_validate_url_string_upgrades_ip_address(clear_tls_cache, get_good):
    url_string = 'http://8.8.8.8'
    actual_validated_url = urls.validate_url_string(url_string)
    expect_validated_url = 'https://8.8.8.8'
    assert actual_validated_url == expect_validated_url


def test_validate_url_string_adds_to_ip_address(clear_tls_cache, get_good):
    url_string = '8.8.8.8'
    actual_validated_url = urls.validate_url_string(url_string)
    expect_validated_url = 'https://8.8.8.8'
    assert actual_validated_url == expect_validated_url


def test_validate_url_string_handles_wmc_type_scheme(
        clear_tls_cache, get_good
):
    url_string = '//commons.wikimedia.org/wiki/User:potato'
    actual_validated_url = urls.validate_url_string(url_string)
    expect_validated_url = 'https://commons.wikimedia.org/wiki/User:potato'
    assert actual_validated_url == expect_validated_url


def test_validate_url_string_caches_tls_support(clear_tls_cache, monkeypatch):
    url_string = 'commons.wikimedia.org/wiki/User:potato'
    with patch.object(
            urls.requests, 'get', return_value=requests.Response()
    ) as mock_get:
        actual_validated_url_1 = urls.validate_url_string(url_string)
        actual_validated_url_2 = urls.validate_url_string(url_string)
    expect_validated_url = 'https://commons.wikimedia.org/wiki/User:potato'
    assert actual_validated_url_1 == expect_validated_url
    assert actual_validated_url_2 == expect_validated_url
    mock_get.assert_called_once()


def test_rewrite_redirected_url_returns_when_ok(
        clear_rewriter_cache, monkeypatch
):
    expect_url = 'https://rewritten.url'
    r = requests.Response()
    r.status_code = 200
    r.url = expect_url
    monkeypatch.setattr(urls.requests, 'get', lambda *args: r)
    actual_url = urls.rewrite_redirected_url('https://input.url')
    assert actual_url == expect_url


def test_rewrite_redirected_url_nones_when_not_ok(
        clear_rewriter_cache, monkeypatch
):
    r = requests.Response()
    r.status_code = 404
    r.url = 'https://rewritten.url'
    monkeypatch.setattr(urls.requests, 'get', lambda *args: r)
    actual_url = urls.rewrite_redirected_url('https://input.url')
    assert actual_url is None


def test_rewrite_redirected_url_nones_when_error_occurs(
        clear_rewriter_cache, monkeypatch
):
    def mock_get(*args):
        raise Exception
    monkeypatch.setattr(urls.requests, 'get', mock_get)
    actual_url = urls.rewrite_redirected_url('https://input.url')
    assert actual_url is None


def test_rewrite_redirected_url_caches_results(
        clear_rewriter_cache, monkeypatch
):
    expect_url = 'https://rewritten.url'
    r = requests.Response()
    r.status_code = 200
    r.url = expect_url
    input_url = 'https://rewritten.url'
    with patch.object(urls.requests, 'get', return_value=r) as mock_get:
        actual_rewritten_url_1 = urls.rewrite_redirected_url(input_url)
        actual_rewritten_url_2 = urls.rewrite_redirected_url(input_url)
    assert actual_rewritten_url_1 == expect_url
    assert actual_rewritten_url_2 == expect_url
    mock_get.assert_called_once()


def test_add_url_scheme_adds_scheme():
    url_stub = 'creativecommons.org'
    actual_url = urls.add_url_scheme(url_stub, scheme='https')
    expect_url = 'https://creativecommons.org'
    assert actual_url == expect_url


def test_add_url_scheme_upgrades_scheme():
    url_stub = 'http://creativecommons.org'
    actual_url = urls.add_url_scheme(url_stub, scheme='https')
    expect_url = 'https://creativecommons.org'
    assert actual_url == expect_url


def test_add_url_scheme_leaves_scheme():
    url_stub = 'http://creativecommons.org'
    actual_url = urls.add_url_scheme(url_stub, scheme='http')
    expect_url = 'http://creativecommons.org'
    assert actual_url == expect_url


def test_add_url_scheme_handles_h():
    url_stub = 'hreativecommons.org/h'
    actual_url = urls.add_url_scheme(url_stub, scheme='https')
    expect_url = 'https://hreativecommons.org/h'
    assert actual_url == expect_url


def test_add_url_scheme_leaves_nonprefix_scheme():
    url_stub = 'hreativecommons.org/?referer=https://abc.com'
    actual_url = urls.add_url_scheme(url_stub, scheme='https')
    expect_url = 'https://hreativecommons.org/?referer=https://abc.com'
    assert actual_url == expect_url
