"""Database Connection Module"""
import uuid

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy import text
from normbase.config import settings

# Convert database URL based on type
database_url = settings.database_url

# For PostgreSQL, use asyncpg driver
if database_url.startswith("postgresql://"):
    database_url = database_url.replace("postgresql://", "postgresql+asyncpg://", 1)

# Engine configuration
engine_kwargs = {
    "echo": settings.api_debug,
}

# SQLite specific settings
if "sqlite" in database_url:
    engine_kwargs["connect_args"] = {"check_same_thread": False}
else:
    engine_kwargs["pool_pre_ping"] = True
    engine_kwargs["pool_size"] = 10
    engine_kwargs["max_overflow"] = 20

engine = create_async_engine(database_url, **engine_kwargs)

async_session_maker = async_sessionmaker(
    engine,
    class_=AsyncSession,
    expire_on_commit=False,
)


class Base(DeclarativeBase):
    """Base class for all database models"""
    pass


async def get_db() -> AsyncSession:
    """Dependency for getting database session"""
    async with async_session_maker() as session:
        yield session


async def init_db():
    """Initialize database tables"""
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
        # Ensure fields table exists for field-scoped retrieval.
        await conn.execute(
            text(
                """
                CREATE TABLE IF NOT EXISTS fields (
                    id UUID PRIMARY KEY,
                    name VARCHAR(255) UNIQUE,
                    org_id UUID,
                    description TEXT,
                    active BOOLEAN DEFAULT TRUE,
                    created_at TIMESTAMPTZ DEFAULT NOW(),
                    updated_at TIMESTAMPTZ DEFAULT NOW()
                );
                """
            )
        )
        # Seed default field on first initialization.
        await conn.execute(
            text(
                """
                INSERT INTO fields (id, name, description, active, created_at, updated_at)
                VALUES (:id, 'default', 'Default field for all norms', TRUE, NOW(), NOW())
                ON CONFLICT (name) DO NOTHING;
                """
            ),
            {"id": str(uuid.uuid4())},
        )
        # Postgres-safe schema evolution for usage token replay controls.
        if "sqlite" not in database_url:
            await conn.execute(
                text(
                    """
                    ALTER TABLE IF EXISTS api_keys
                    ADD COLUMN IF NOT EXISTS scopes JSONB DEFAULT '["*"]';
                    """
                )
            )
            await conn.execute(
                text(
                    """
                    ALTER TABLE IF EXISTS norm_usage_tokens
                    ADD COLUMN IF NOT EXISTS reported_norm_ids JSONB DEFAULT '[]';
                    """
                )
            )
            await conn.execute(
                text(
                    """
                    ALTER TABLE IF EXISTS norm_usage_tokens
                    ADD COLUMN IF NOT EXISTS closed_at TIMESTAMPTZ;
                    """
                )
            )


async def close_db():
    """Close database connections"""
    await engine.dispose()
