"""
Database configuration generator.

Generates async database setup for SQLModel/SQLAlchemy.
"""

from ..base import BaseGenerator
from ...ir.models import GeneratedFile


class DatabaseConfigGenerator(BaseGenerator):
    """
    Generates database.py with async engine and session setup.
    """

    def generate(self) -> list[GeneratedFile]:
        """Generate database configuration file."""
        content = self._generate_database_config()
        return [self.create_file("database.py", content)]

    def _generate_database_config(self) -> str:
        """Generate database.py content."""
        if self.config.async_mode:
            return self._generate_async_config()
        return self._generate_sync_config()

    def _generate_async_config(self) -> str:
        """Generate async database configuration."""
        env_var = self.config.database_env_var
        default_url = self.config.database_default_url
        # Define outside f-string to avoid escaping issues
        connect_args_async = '{"ssl": False}'

        return f'''"""
Async database configuration for FastAPI.

Auto-generated by django-cfg FastAPI ORM Generator.

Usage:
    from .database import get_session, init_db

    # In FastAPI app startup
    @app.on_event("startup")
    async def startup():
        await init_db()

    # In endpoints
    @app.get("/items")
    async def get_items(session: AsyncSession = Depends(get_session)):
        ...
"""

import os
from typing import AsyncGenerator

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
from sqlmodel import SQLModel


# Database URL from environment or Django settings
DATABASE_URL = os.getenv(
    "{env_var}",
    "{default_url}"
)

# Convert postgres:// to postgresql+asyncpg:// if needed
if DATABASE_URL.startswith("postgres://"):
    DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql+asyncpg://", 1)
elif DATABASE_URL.startswith("postgresql://") and "+asyncpg" not in DATABASE_URL:
    DATABASE_URL = DATABASE_URL.replace("postgresql://", "postgresql+asyncpg://", 1)


# Create async engine
# Note: connect_args with ssl=False is for asyncpg driver
# (sslmode=disable in URL only works with psycopg2/libpq, not asyncpg)
engine = create_async_engine(
    DATABASE_URL,
    echo=False,  # Set to True for SQL logging
    future=True,
    pool_pre_ping=True,
    pool_size=5,
    max_overflow=10,
    connect_args={connect_args_async},  # Disable SSL for local development
)

# Create async session factory
async_session_factory = sessionmaker(
    engine,
    class_=AsyncSession,
    expire_on_commit=False,
    autocommit=False,
    autoflush=False,
)


async def init_db() -> None:
    """
    Initialize database tables.

    Note: In production, use Alembic migrations instead of create_all().
    This is mainly for development/testing.
    """
    async with engine.begin() as conn:
        # Uncomment to create all tables (development only)
        # await conn.run_sync(SQLModel.metadata.create_all)
        pass


async def get_session() -> AsyncGenerator[AsyncSession, None]:
    """
    Get async database session.

    Use as FastAPI dependency:
        @app.get("/items")
        async def get_items(session: AsyncSession = Depends(get_session)):
            ...
    """
    async with async_session_factory() as session:
        try:
            yield session
        except Exception:
            await session.rollback()
            raise
        # Note: async context manager handles close() automatically


# Optional: Context manager for scripts
class DatabaseSession:
    """
    Context manager for database sessions in scripts.

    Usage:
        async with DatabaseSession() as session:
            result = await session.execute(...)
    """

    async def __aenter__(self) -> AsyncSession:
        self.session = async_session_factory()
        return self.session

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        try:
            if exc_type:
                await self.session.rollback()
        finally:
            await self.session.close()
'''

    def _generate_sync_config(self) -> str:
        """Generate sync database configuration."""
        env_var = self.config.database_env_var
        # For sync mode, use standard postgresql:// instead of asyncpg
        default_url = self.config.database_default_url.replace("+asyncpg", "")
        # Define outside f-string to avoid escaping issues
        connect_args_sync = '{"sslmode": "disable"}'

        return f'''"""
Sync database configuration for FastAPI.

Auto-generated by django-cfg FastAPI ORM Generator.
"""

import os
from typing import Generator

from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from sqlmodel import SQLModel


# Database URL from environment
DATABASE_URL = os.getenv(
    "{env_var}",
    "{default_url}"
)

# Create sync engine
# Note: For psycopg2, use sslmode in connect_args
engine = create_engine(
    DATABASE_URL,
    echo=False,
    pool_pre_ping=True,
    pool_size=5,
    max_overflow=10,
    connect_args={connect_args_sync},  # Disable SSL for local development
)

# Create session factory
SessionLocal = sessionmaker(
    engine,
    class_=Session,
    expire_on_commit=False,
    autocommit=False,
    autoflush=False,
)


def init_db() -> None:
    """Initialize database tables."""
    # In production, use Alembic migrations
    # SQLModel.metadata.create_all(engine)
    pass


def get_session() -> Generator[Session, None, None]:
    """Get database session."""
    session = SessionLocal()
    try:
        yield session
    except Exception:
        session.rollback()
        raise
    finally:
        session.close()
'''
