import logging

import oracledb
from typing import List, Dict, Any, Optional
from contextlib import contextmanager

logger = logging.getLogger(__name__)


class OracleClient:
    def __init__(self, user: str, password: str, dsn: str):
        self.user = user
        self.password = password
        self.dsn = dsn
        self._pool: Optional[oracledb.ConnectionPool] = None
        self._connected = False

    def connect(self) -> None:
        try:
            test_conn = oracledb.connect(
                user=self.user,
                password=self.password,
                dsn=self.dsn,
            )
            test_conn.ping()
            test_conn.close()

            self._pool = oracledb.create_pool(
                user=self.user,
                password=self.password,
                dsn=self.dsn,
                min=1,
                max=10,
                increment=1,
            )
            self._connected = True
            logger.info(f"Pool Oracle conectado: {self.dsn}")
        except oracledb.Error as e:
            logger.error(f"Oracle database error: {e}")
            self._connected = False
        except Exception as e:
            logger.error(f"Oracle connection error: {e}")
            self._connected = False

    def close(self) -> None:
        if self._pool:
            try:
                self._pool.close()
            except oracledb.Error:
                pass

    @property
    def is_connected(self) -> bool:
        return self._connected and self._pool is not None

    @contextmanager
    def get_connection(self):
        if not self._pool:
            raise RuntimeError("Pool Oracle não conectado. Execute connect() primeiro.")
        conn = None
        try:
            conn = self._pool.acquire()
            yield conn
        finally:
            if conn:
                self._pool.release(conn)

    def executar_query(self, query: str, params: Optional[dict] = None) -> List[Dict[str, Any]]:
        if not self.is_connected:
            return []
        try:
            with self.get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute(query, params or {})
                columns = [col[0] for col in cursor.description]
                rows = cursor.fetchall()

                results = []
                for row in rows:
                    row_dict = {}
                    for i, col in enumerate(columns):
                        value = row[i]
                        if hasattr(value, 'read'):
                            value = value.read()
                        row_dict[col] = value
                    results.append(row_dict)

                cursor.close()
                return results
        except Exception as e:
            logger.warning(f"Oracle: falha ao executar query: {e}")
            self._connected = False
            return []

    def buscar_coordenacoes_programa(self, id_pessoa: int) -> List[Dict[str, Any]]:
        query = """
            SELECT
                c.ID_PESSOA,
                c.ID_PROGRAMA_SNPG,
                p.NM_PROGRAMA,
                p.CD_PROGRAMA_PPG,
                p.DS_CONCEITO AS NOTA_PPG,
                p.NM_PROGRAMA_MODALIDADE,
                aa.NM_AREA_AVALIACAO,
                c.DT_INICIO_VIGENCIA,
                c.DT_FIM_VIGENCIA
            FROM VM_COORDENADOR c
            INNER JOIN VM_PROGRAMA p
                ON c.ID_PROGRAMA_SNPG = p.ID_PROGRAMA
            LEFT JOIN VM_AREA_CONHECIMENTO ac
                ON p.ID_AREA_CONHECIMENTO_ATUAL = ac.ID_AREA_CONHECIMENTO
            LEFT JOIN VM_AREA_AVALIACAO aa
                ON ac.ID_AREA_AVALIACAO = aa.ID_AREA_AVALIACAO
            WHERE c.ID_PESSOA = :id_pessoa
            ORDER BY c.DT_INICIO_VIGENCIA DESC
        """
        return self.executar_query(query, {"id_pessoa": id_pessoa})

    def buscar_todas_coordenacoes_programa(self) -> List[Dict[str, Any]]:
        query = """
            SELECT
                c.ID_PESSOA,
                c.ID_PROGRAMA_SNPG,
                p.NM_PROGRAMA,
                p.CD_PROGRAMA_PPG,
                p.DS_CONCEITO AS NOTA_PPG,
                p.NM_PROGRAMA_MODALIDADE,
                aa.NM_AREA_AVALIACAO,
                c.DT_INICIO_VIGENCIA,
                c.DT_FIM_VIGENCIA
            FROM SUCUPIRA_PAINEL.VM_COORDENADOR c
            INNER JOIN SUCUPIRA_PAINEL.VM_PROGRAMA_SUCUPIRA p
                ON c.ID_PROGRAMA_SNPG = p.ID_PROGRAMA
            LEFT JOIN SUCUPIRA_PAINEL.VM_AREA_CONHECIMENTO ac
                ON p.ID_AREA_CONHECIMENTO_ATUAL = ac.ID_AREA_CONHECIMENTO
            LEFT JOIN SUCUPIRA_PAINEL.VM_AREA_AVALIACAO aa
                ON ac.ID_AREA_AVALIACAO = aa.ID_AREA_AVALIACAO
            ORDER BY c.ID_PESSOA, c.DT_INICIO_VIGENCIA DESC
        """
        return self.executar_query(query)
