"""Gatekeeper: Source map accuracy and performance."""

import pytest

from pyfuse.web.compiler.pyfusebyte import PyFuseCompiler
from pyfuse.web.compiler.sourcemap import SourceMap


@pytest.mark.gatekeeper
class TestSourceMapGatekeeper:
    """Verify source maps accurately map PC to line numbers."""

    def test_sourcemap_maps_all_statements(self) -> None:
        """Every statement in source should have a mapping."""
        source = """count = Signal(0)
name = Signal("test")

def increment():
    count.value += 1

with Div():
    Text("Hello")
"""
        compiler = PyFuseCompiler()
        _, _, fsm = compiler.compile_full(source, filename="test.py")

        sm = SourceMap.from_bytes(fsm)
        lines = {m[2] for m in sm.mappings}

        # Should have mappings for key lines
        assert 1 in lines  # count = Signal(0)
        assert 2 in lines  # name = Signal("test")
        # Line 4-5 (function def) may or may not emit opcodes
        assert 7 in lines  # with Div():
        assert 8 in lines  # Text("Hello")

    def test_sourcemap_lookup_accuracy(self) -> None:
        """lookup_pc returns correct line for generated bytecode."""
        source = """count = Signal(0)
other = Signal(1)
"""
        compiler = PyFuseCompiler()
        _fbc, _, fsm = compiler.compile_full(source, filename="app.py")

        sm = SourceMap.from_bytes(fsm)

        # First opcode should map to line 1
        result = sm.lookup_pc(0)
        assert result is not None
        file, line = result
        assert file == "app.py"
        assert line == 1

    def test_sourcemap_binary_size_reasonable(self) -> None:
        """Source map should be compact (< 20 bytes per mapping)."""
        source = "\n".join([f"sig{i} = Signal({i})" for i in range(100)])

        compiler = PyFuseCompiler()
        _, _, fsm = compiler.compile_full(source, filename="app.py")

        sm = SourceMap.from_bytes(fsm)
        bytes_per_mapping = len(fsm) / max(len(sm.mappings), 1)

        # Each mapping is 10 bytes (pc:4 + file:2 + line:4)
        # Plus file table overhead, should be < 20 bytes/mapping
        assert bytes_per_mapping < 20, (
            f"Source map too large: {bytes_per_mapping:.1f} bytes/mapping"
        )

        print(f"\n[SourceMap Gatekeeper] {len(sm.mappings)} mappings in {len(fsm)} bytes")
        print(f"[SourceMap Gatekeeper] {bytes_per_mapping:.1f} bytes/mapping")
