import uuid

from sqlalchemy import String
from sqlalchemy.orm import Mapped, mapped_column

from iurban_tenancy import (
    NAMING_CONVENTION,
    Base,
    TenantMixin,
    TimestampMixin,
    UuidPkMixin,
    apply_tenant,
    metadata,
    rls_ddl,
)


class Thing(UuidPkMixin, TenantMixin, TimestampMixin, Base):
    __tablename__ = "things"
    name: Mapped[str] = mapped_column(String(50))


def test_mixins_add_the_canonical_columns():
    cols = set(Thing.__table__.columns.keys())
    assert {"id", "tenant_id", "created_at", "updated_at", "name"} <= cols


def test_tenant_id_is_indexed_and_not_null():
    col = Thing.__table__.columns["tenant_id"]
    assert col.nullable is False
    assert col.index is True


def test_naming_convention_on_metadata():
    assert metadata.naming_convention == NAMING_CONVENTION


def test_rls_ddl_emits_enable_force_and_policy():
    sql = rls_ddl("things")
    assert "ENABLE ROW LEVEL SECURITY" in sql
    assert "FORCE ROW LEVEL SECURITY" in sql
    assert "CREATE POLICY tenant_isolation ON things" in sql
    assert "current_setting('app.current_tenant')" in sql


class _FakeSession:
    def __init__(self) -> None:
        self.calls: list[tuple[str, dict]] = []

    async def execute(self, stmt, params=None):
        self.calls.append((str(stmt), params or {}))


async def test_apply_tenant_runs_set_local_with_the_tenant():
    s = _FakeSession()
    tid = uuid.uuid4()
    await apply_tenant(s, tid)  # type: ignore[arg-type]
    sql, params = s.calls[0]
    assert "SET LOCAL app.current_tenant" in sql
    assert params == {"tid": str(tid)}
