from crawler_cluster.browser_worker import BrowserWorker
from lxml.html import HtmlElement
import pytest
import pytest_asyncio
from pathlib import Path
import asyncio
import json

static_dir = Path(__file__).parent.absolute().joinpath('static')

antibot_url = f"file:///{static_dir.joinpath('Antibot.html')}"
interactions_url = f"file:///{static_dir.joinpath('interactions.html')}"
blocked_url = f"file:///{static_dir.joinpath('blocked.html')}"

pytestmark = pytest.mark.asyncio


@pytest.fixture
async def worker():
    worker = BrowserWorker(disable_images=True, garbage_collect_at=500, launch_options={
                           'ignoreDefaultArgs': '--disable-extensions'})
    #worker = BrowserWorker()
    ok = await worker.launch()
    assert ok
    yield worker
    await worker.shutdown()


async def test_fingerprint(worker):
    # await worker.try_get('https://bot.sannysoft.com/')
    await worker.try_get(antibot_url)
    await worker.page.screenshot(path='browser_fingerprint.png', fullPage=True)


async def test_page_content(worker):
    resp = await worker.try_get(antibot_url)
    assert resp.status == 0
    assert isinstance(worker.html, str)
    assert isinstance(worker.text, str)
    assert isinstance(worker.root, HtmlElement)


async def test_cookies(worker):
    cookie = {'name': 'cookie', 'value': 'chocolate chip',
              'domain': 'cookie.com', 'secure': False, 'sameSite': 'Lax'}
    ok = await worker.set_cookie(cookie)
    assert ok
    ok = await worker.clear_cookies()
    assert ok
    cookies = await worker.page.cookies()
    assert len(cookies) == 0


async def test_cdp(worker):
    ok = worker.set_default_nav_timeout(60_000)
    assert ok
    ok = await worker.set_ad_block(True)
    assert ok


async def test_blocked_urls(worker):
    ok = await worker.set_blocked_urls(['saved_resource'])
    await worker.try_get(antibot_url)
    content = await worker.evaluate(
        '() => JSON.stringify(performance.getEntries(), null, "  ")')
    names = [d.get('name') for d in json.loads(content)]
    assert not any('saved_resource' in name for name in names)


async def test_request_abort_types(worker):
    no_load = ['image', 'font', 'stylesheet', 'script', 'img']
    ok = await worker.set_request_abort_types(no_load)
    assert ok


async def test_disable_images(worker):
    await worker.try_get(antibot_url)
    content = await worker.evaluate('() => JSON.stringify(performance.getEntries(), null, "  ")')
    images = [d for d in json.loads(
        content) if d.get('initiatorType') in ('image', 'img')]
    assert len(images) == 0


async def test_evaluate_on_new_doc(worker):
    ok = await worker.evaluate_on_new_doc("() => document.getElementById('title').setAttribute('id', 'awesome');")
    assert ok


async def test_redirect_block(worker):
    ok = await worker.set_redirect_blocking_enabled(True)
    assert ok
    await worker.try_get(f"file:///{static_dir.joinpath('redirect_from.html')}")
    assert 'redirect_to' not in worker.page.url


async def test_scroll(worker):
    await worker.try_get(antibot_url)
    ok = await worker.scroll()
    assert ok


async def test_hover(worker):
    await worker.try_get(interactions_url)
    ok = await worker.hover('//th[@onmouseover]')
    assert ok


async def test_click_js_element(worker):
    await worker.try_get(interactions_url)
    ok = await worker.click_js_element('//table[@onclick]')
    assert ok


async def test_error_status(worker):
    # record more than 4 consecutive browser errors.
    await worker._record_error_status(True)
    await worker._record_error_status(True)
    await worker._record_error_status(True)
    await worker._record_error_status(True)
    await worker._record_error_status(True)
    assert not worker.ok


async def test_function_wait(worker):
    async def sleep_long(sleep_time):
        await asyncio.sleep(sleep_time)
        return 0
    ok, result = await worker._wait_for(sleep_long, wait_for_timeout=3, sleep_time=4)
    assert not ok
    assert result is None
    assert worker._consecutive_errors == 1


async def test_block_detection(worker):
    await worker.try_get(blocked_url)
    assert worker.probability_blocked == 3
