"""
Oracle Database Connection Pool - Shared între toate aplicațiile ROA2WEB
Folosește oracledb cu connection pooling pentru performance optimă
"""
import oracledb
import os
from contextlib import asynccontextmanager
from typing import Optional
import logging

logger = logging.getLogger(__name__)

class OraclePool:
    """
    Singleton class pentru Oracle connection pool
    Partajat între toate microservicele ROA2WEB
    """
    _instance: Optional['OraclePool'] = None
    _pool: Optional[oracledb.ConnectionPool] = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(OraclePool, cls).__new__(cls)
        return cls._instance
    
    async def initialize(self, **config):
        """Inițializează pool-ul de conexiuni"""
        if self._pool is None:
            # Check if we have DSN or individual parameters
            dsn = config.get('dsn', os.getenv('ORACLE_DSN'))
            if dsn:
                # Use DSN connection
                self._pool = oracledb.create_pool(
                    user=config.get('user', os.getenv('ORACLE_USER')),
                    password=config.get('password', os.getenv('ORACLE_PASSWORD')),
                    dsn=dsn,
                    min=config.get('min_connections', 2),
                    max=config.get('max_connections', 10),
                    increment=config.get('increment', 1),
                    getmode=oracledb.POOL_GETMODE_WAIT
                )
            else:
                # Use individual parameters (host, port, service_name or sid)
                # Prefer SERVICE_NAME over SID (more modern Oracle approach)
                service_name = config.get('service_name', os.getenv('ORACLE_SERVICE_NAME'))
                sid = config.get('sid', os.getenv('ORACLE_SID'))

                pool_params = {
                    'user': config.get('user', os.getenv('ORACLE_USER')),
                    'password': config.get('password', os.getenv('ORACLE_PASSWORD')),
                    'host': config.get('host', os.getenv('ORACLE_HOST', 'localhost')),
                    'port': config.get('port', int(os.getenv('ORACLE_PORT', '1526'))),
                    'min': config.get('min_connections', 2),
                    'max': config.get('max_connections', 10),
                    'increment': config.get('increment', 1),
                    'getmode': oracledb.POOL_GETMODE_WAIT
                }

                # Use service_name if available, otherwise fall back to sid
                if service_name:
                    pool_params['service_name'] = service_name
                    logger.info(f"Using SERVICE_NAME: {service_name}")
                elif sid:
                    pool_params['sid'] = sid
                    logger.info(f"Using SID: {sid}")
                else:
                    # Default fallback
                    pool_params['service_name'] = 'ROA'
                    logger.info("Using default SERVICE_NAME: ROA")

                self._pool = oracledb.create_pool(**pool_params)
            logger.info(f"Oracle pool created with {self._pool.opened} connections")
    
    @asynccontextmanager
    async def get_connection(self):
        """Context manager pentru obținerea unei conexiuni din pool"""
        if self._pool is None:
            raise RuntimeError("Pool not initialized. Call initialize() first.")
        
        connection = None
        try:
            connection = self._pool.acquire()
            logger.debug("Connection acquired from pool")
            yield connection
        finally:
            if connection is not None:
                connection.close()
                logger.debug("Connection returned to pool")

    
    async def execute_query(self, query: str, parameters=None):
        """
        Execute a SQL query and return all results
        Based on official Oracle python-oracledb patterns
        """
        if self._pool is None:
            raise RuntimeError("Pool not initialized. Call initialize() first.")
        
        connection = None
        try:
            connection = self._pool.acquire()
            logger.debug(f"Executing query: {query[:100]}...")
            
            with connection.cursor() as cursor:
                if parameters:
                    cursor.execute(query, parameters)
                else:
                    cursor.execute(query)
                
                # Check if this is a SELECT statement
                if query.strip().upper().startswith('SELECT') or query.strip().upper().startswith('WITH'):
                    return cursor.fetchall()
                else:
                    # For DML statements, return affected row count
                    connection.commit()
                    return cursor.rowcount
                    
        except Exception as e:
            if connection:
                connection.rollback()
            logger.error(f"Query execution failed: {str(e)}")
            raise
        finally:
            if connection is not None:
                connection.close()
                logger.debug("Connection returned to pool")
    
    async def close_pool(self):
        """Închide pool-ul de conexiuni"""
        if self._pool is not None:
            self._pool.close()
            self._pool = None
            logger.info("Oracle pool closed")

# Instance globală pentru folosire în toate aplicațiile
oracle_pool = OraclePool()