import pytest
import pytest_asyncio
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine

from app.core.networking import lowest_free_onu_id, map_vlan, map_vlan_from_db
from app.models.models import Base, Customer, VlanMappingRule


@pytest_asyncio.fixture
async def session():
    engine = create_async_engine("sqlite+aiosqlite:///:memory:")
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    factory = async_sessionmaker(engine, expire_on_commit=False)
    async with factory() as db:
        yield db
    await engine.dispose()


def test_default_vlan_mapping_is_explicit():
    assert map_vlan(175) == 15
    assert map_vlan(172) == 10
    assert map_vlan(999) == 999


@pytest.mark.asyncio
async def test_database_vlan_rule_overrides_default(session):
    session.add(VlanMappingRule(source_vlan=175, target_vlan=25, purpose="service"))
    await session.commit()
    assert await map_vlan_from_db(session, 175) == 25


@pytest.mark.asyncio
async def test_lowest_free_onu_id_is_scoped_to_olt_port(session):
    session.add_all([
        Customer(name="one", olt_port="1/1/1", onu_id=1),
        Customer(name="three", olt_port="1/1/1", onu_id=3),
        Customer(name="other", olt_port="1/1/2", onu_id=1),
    ])
    await session.commit()
    assert await lowest_free_onu_id(session, "1/1/1", end=4) == 2
    assert await lowest_free_onu_id(session, "1/1/2", end=4) == 2
    assert await lowest_free_onu_id(session, "1/1/1", start=1, end=1) is None


@pytest.mark.asyncio
async def test_lowest_free_onu_id_rejects_bad_range(session):
    with pytest.raises(ValueError):
        await lowest_free_onu_id(session, "1/1/1", start=0)
