
import pytest
import pytest_asyncio
import asyncio
import time
from unittest.mock import MagicMock, patch, AsyncMock
from core.browser_controller import BrowserController, NavigationStatus

# Shared HTML Template for Visual Chaos
CHAOS_HTML = """
<!DOCTYPE html>
<html>
<head>
    <style>
        .moving-target { position: absolute; width: 50px; height: 50px; background: red; transition: all 0.1s; }
        .occluder { position: absolute; z-index: 9999; background: black; opacity: 0.9; }
        .canvas-text { border: 1px solid blue; }
        body { margin: 0; padding: 0; overflow: hidden; }
    </style>
</head>
<body>
    <div id="container"></div>
    <canvas id="ocr-canvas" width="200" height="50"></canvas>
    <script>
        // JS Chaos Injection
        window.startChaos = () => {
            const container = document.getElementById('container');
            // Create 100 moving elements
            for(let i=0; i<100; i++) {
                let div = document.createElement('div');
                div.className = 'moving-target';
                div.id = 'target-' + i;
                container.appendChild(div);
            }
            // Move them loop
            setInterval(() => {
                document.querySelectorAll('.moving-target').forEach(el => {
                    el.style.left = Math.random() * window.innerWidth + 'px';
                    el.style.top = Math.random() * window.innerHeight + 'px';
                });
            }, 50); // 20 FPS updates
        };
        
        // Canvas Text
        const ctx = document.getElementById('ocr-canvas').getContext('2d');
        ctx.font = '20px Arial';
        ctx.fillText('Hello Chaos', 10, 30);
    </script>
</body>
</html>
"""

@pytest_asyncio.fixture
async def browser():
    controller = BrowserController()
    initialized = await controller.initialize()
    if not initialized:
        yield None
    else:
        yield controller
        await controller.close()

# UVS-A11: 100 Moving Elements
@pytest.mark.asyncio
async def test_moving_elements_performance(browser):
    """Verify system stability with 100 rapidly moving DOM elements."""
    if not browser: pytest.skip("Browser init failed")
    
    # Load chaos page
    await browser.navigate("data:text/html," + CHAOS_HTML)
    
    # Inject chaos directly (no sync window function dependency)
    js = """
    (() => {
        const container = document.getElementById('container');
        for(let i=0; i<100; i++) {
            let div = document.createElement('div');
            div.className = 'moving-target';
            div.id = 'target-' + i;
            container.appendChild(div);
        }
        setInterval(() => {
            document.querySelectorAll('.moving-target').forEach(el => {
                el.style.left = Math.random() * window.innerWidth + 'px';
                el.style.top = Math.random() * window.innerHeight + 'px';
            });
        }, 50);
    })();
    """
    await browser._active_backend._page.evaluate(js)
    
    # Let it run for 2 seconds
    await asyncio.sleep(2.0)
    
    # Verify browser didn't crash
    is_alive = await browser._active_backend.is_available()
    assert is_alive
    
    # Verify we can still get a computed style
    pos = await browser._active_backend._page.evaluate("document.getElementById('target-0').style.left")
    assert pos != "" 

# UVS-A12: CSS Transform Scale
@pytest.mark.asyncio
async def test_css_transform_scale(browser):
    """Verify coordinate mapping (implied) on scaled body."""
    if not browser: pytest.skip("Browser init failed")
    
    html = """<body style="transform: scale(0.5); transform-origin: 0 0; width: 200%; height: 200%;">
              <button id="btn" style="position:absolute; left:100px; top:100px; width:100px; height:100px;">Click Me</button>
              </body>"""
    await browser.navigate("data:text/html," + html)

    try:
        await browser._active_backend._page.click("#btn")
        assert True
    except Exception as e:
        pytest.fail(f"Failed to click scaled element: {e}")

# UVS-A13: Element Occlusion
@pytest.mark.asyncio
async def test_element_occlusion(browser):
    """Verify click fails or handles occlusion correctly."""
    if not browser: pytest.skip("Browser init failed")
    
    html = """
    <button id="target" onclick="window.clicked=true">Target</button>
    <div style="position:absolute; top:0; left:0; width:100%; height:100%; background:red; z-index:9999;" id="blocker"></div>
    """
    await browser.navigate("data:text/html," + html)
    
    try:
        await browser._active_backend._page.click("#target", timeout=1000)
        pytest.fail("Should have raised error due to occlusion")
    except Exception as e:
        assert "intersects" in str(e) or "receiving the click" in str(e) or "Timeout" in str(e)

# UVS-A14: Background Flash (Epileptic Chaos)
@pytest.mark.asyncio
async def test_background_flash_stability(browser):
    """Verify browser stability under 20Hz flashing."""
    if not browser: pytest.skip("Browser init failed")
    
    js = """
    setInterval(() => {
        document.body.style.backgroundColor = document.body.style.backgroundColor == 'red' ? 'blue' : 'red';
    }, 50);
    """
    await browser.navigate("data:text/html,<body>Flash</body>")
    await browser._active_backend._page.evaluate(js)
    await asyncio.sleep(1.0)
    assert await browser._active_backend.is_available()

# UVS-A15: Non-Standard Viewport
@pytest.mark.asyncio
async def test_weird_viewport(browser):
    """Verify layout handling on 400x3000 viewport."""
    if not browser: pytest.skip("Browser init failed")
    
    await browser._active_backend._page.set_viewport_size({"width": 400, "height": 3000})
    await browser.navigate("data:text/html,<div>Long Body</div>")
    
    size = browser._active_backend._page.viewport_size
    assert size['width'] == 400
    assert await browser._active_backend.is_available()

# UVS-A16: Canvas OCR Fallback
@pytest.mark.asyncio
async def test_canvas_presence(browser):
    """Verify page with canvas loads and is accessible."""
    if not browser: pytest.skip("Browser init failed")
    
    await browser.navigate("data:text/html," + CHAOS_HTML)
    el = await browser.find_element("#ocr-canvas")
    assert el.found

# UVS-A17: Z-Index Chaos
@pytest.mark.asyncio
async def test_z_index_chaos(browser):
    """Verify interaction with high Z-index elements."""
    if not browser: pytest.skip("Browser init failed")
    
    html = """
    <div id="bottom" style="z-index:1; position:absolute;">Bottom</div>
    <div id="top" style="z-index:999999; position:absolute;">Top</div>
    """
    await browser.navigate("data:text/html," + html)
    el_top = await browser.find_element("#top")
    assert el_top.found

# UVS-A18: Infinite Scroll
@pytest.mark.asyncio
async def test_infinite_scroll_stability(browser):
    """Verify stability during rapid content appending."""
    if not browser: pytest.skip("Browser init failed")
    
    html = """
    <div id="content"></div>
    <script>
    function add() {
        for(let i=0; i<10; i++) {
            let d = document.createElement('div');
            d.innerText = 'Item ' + Date.now();
            document.getElementById('content').appendChild(d);
        }
    }
    setInterval(add, 100);
    </script>
    """
    await browser.navigate("data:text/html," + html)
    await asyncio.sleep(2.0)
    count = await browser._active_backend._page.evaluate("document.getElementById('content').children.length")
    assert count > 50

# UVS-A19: Invisible Elements
@pytest.mark.asyncio
async def test_invisible_elements(browser):
    """Verify handling of opacity:0 and display:none."""
    if not browser: pytest.skip("Browser init failed")
    
    html = """
    <div id="hidden" style="display:none">Hidden</div>
    <div id="invisible" style="opacity:0">Invisible</div>
    """
    await browser.navigate("data:text/html," + html)
    
    hidden = await browser._active_backend._page.query_selector("#hidden")
    inv = await browser._active_backend._page.query_selector("#invisible")
    
    assert await hidden.is_visible() == False
    
    # Playwright considers opacity:0 as VISIBLE unless specifically checking for visual regression.
    # It interacts with layout. So we assert True for existence, but maybe check computed style if needed.
    # For this audit, we just want to ensure we don't crash and can detect them.
    assert await inv.is_visible() == True 

# UVS-A20: WebGL Context Loss (Simulation)
@pytest.mark.asyncio
async def test_webgl_context_loss(browser):
    """Verify recovery or non-crash on WebGL context loss event."""
    if not browser: pytest.skip("Browser init failed")
    
    html = """<canvas id="gl"></canvas>
    <script>
    const canvas = document.getElementById('gl');
    const gl = canvas.getContext('webgl');
    const ext = gl.getExtension('WEBGL_lose_context');
    if(ext) setTimeout(() => ext.loseContext(), 100);
    </script>"""
    
    await browser.navigate("data:text/html," + html)
    await asyncio.sleep(1.0)
    assert await browser._active_backend.is_available()

if __name__ == "__main__":
    # pass
    pytest.main([__file__])
