from logging_config import get_logger

logger = get_logger(__name__)

class OracleDB:

    def __init__(self, connector):
        self.connector = connector

    def fetch_all(self, sql, params=None):
        conn = None
        cur = None
        try:
            conn = self.connector.get_connection()
            cur = conn.cursor()

            cur.execute(sql, params or {})

            cols = [c[0] for c in cur.description]
            rows = [dict(zip(cols, r)) for r in cur.fetchall()]

            logger.info("Fetched %s rows from database", len(rows))

            return rows

        except Exception:
            logger.exception("Error in fetch_all")
            raise

        finally:
            if cur:
                cur.close()
            if conn:
                conn.close()

    def execute(self, sql, params):
        conn = None
        cur = None
        try:
            conn = self.connector.get_connection()
            cur = conn.cursor()

            cur.execute(sql, params)
            conn.commit()

            logger.info("Insert/Update executed successfully")

        except Exception:
            if conn:
                conn.rollback()
            logger.exception("Error executing SQL")
            raise

        finally:
            if cur:
                cur.close()
            if conn:
                conn.close()

    def call_procedure(self, name):
        conn = None
        cur = None
        try:
            conn = self.connector.get_connection()
            cur = conn.cursor()

            logger.info("Calling procedure %s", name)

            try:
                cur.callproc(name)
            except Exception:
                cur.execute(f"BEGIN {name}; END;")

            conn.commit()

            logger.info("Procedure executed successfully")
            return True

        except Exception:
            logger.exception("Procedure call failed")
            return False

        finally:
            if cur:
                cur.close()
            if conn:
                conn.close()