from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session, declarative_base
from typing import Generator

from core.config import settings

Base = declarative_base()  # Used for models

_engine = None
_SessionLocal = None

settings.DB_URL = f"postgresql://{settings.DB_USER}:{settings.DB_PASSWORD}@{settings.DB_HOST}:{settings.DB_PORT}/{settings.DB_NAME}"


def get_engine():
    global _engine
    if _engine is None:
        if not settings.DB_URL:
            raise ValueError("DB_URL is not set in Settings.")
        print(f"Connecting to database at {settings.DB_URL}")
        _engine = create_engine(settings.DB_URL)
        try:
            _engine.connect()
        except Exception:
            raise Exception(
                "Database connection failed. Is the database server running?"
            )
        Base.metadata.create_all(_engine)  # Create tables here
    return _engine


def get_sessionmaker():
    global _SessionLocal
    if _SessionLocal is None:
        engine = get_engine()
        _SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
    return _SessionLocal


def get_db() -> Generator[Session, None, None]:
    SessionLocal = get_sessionmaker()
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
