"""Unit of Work pattern implementation.

This module implements the Unit of Work pattern for managing database transactions.
"""

from typing import Optional
from sqlalchemy.orm import Session

from src.config.database import SessionLocal


class UnitOfWork:
    """Unit of Work for managing database transactions.
    
    Usage:
        with UnitOfWork() as uow:
            user = uow.users.get_by_id(1)
            user.email = "new@email.com"
            uow.users.update(user)
            # Automatically commits on success
    """
    
    def __init__(self, session_factory=SessionLocal):
        """Initialize Unit of Work.
        
        Args:
            session_factory: Factory to create database sessions
        """
        self.session_factory = session_factory
        self._session: Optional[Session] = None
    
    def __enter__(self) -> "UnitOfWork":
        """Enter context manager.
        
        Returns:
            UnitOfWork: Self
        """
        self._session = self.session_factory()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """Exit context manager.
        
        Commits on success, rollbacks on error.
        """
        if exc_type is not None:
            self.rollback()
        else:
            self.commit()
        self.close()
    
    def commit(self) -> None:
        """Commit the current transaction."""
        if self._session:
            self._session.commit()
    
    def rollback(self) -> None:
        """Rollback the current transaction."""
        if self._session:
            self._session.rollback()
    
    def close(self) -> None:
        """Close the session."""
        if self._session:
            self._session.close()
            self._session = None
    
    @property
    def session(self) -> Session:
        """Get the current session.
        
        Returns:
            Session: Current database session
            
        Raises:
            RuntimeError: If session not initialized
        """
        if self._session is None:
            raise RuntimeError("Session not initialized. Use within context manager.")
        return self._session

