from typing import Any, Dict

import pymysql
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
from app.main.engine.enum.DatabaseDialectEnum import DatabaseDialectEnum
from app.main.engine.models.Model import Model
import logging

logger = logging.getLogger()


class Mysql:

    def __init__(self, app, host: str, port: int, user: str, password: str, database: str,
                 params: Dict[str, Any]) -> None:
        self.app = app
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.database = database
        self.params = params
        self.engine = None
        self.connection = None
        self.dialect = None

    def create_spark_connection(self):
        params = {}
        try:
            url = "jdbc:mysql://"+self.host+":"+str(self.port)+"/"+self.database
            properties = {"user": self.user, "password": self.password, "driver": "com.mysql.cj.jdbc.Driver"}
            params["url"] = url
            params["properties"] = properties
        except Exception as e:
            self.app.logger.error(f"Error creando conexión Mysql para pyspark. {e}")
        finally:
            return params

    def get_basic_connection(self):
        try:
            if isinstance(self.connection, type(None)):
                self.connection = pymysql.connect(host=self.host, port=self.port, user=self.user,
                                                  password=self.password, db=self.database)
        except Exception as e:
            self.app.logger.error(f"Error obteniendo conexion básica de Mysql. {e}")
        finally:
            return self.connection

    def get_dialect(self) -> str:
        try:
            dialect = DatabaseDialectEnum.MYSQL.value
            self.dialect = f"{dialect}://{self.user}:{self.password}@{self.host}:{str(self.port)}/{self.database}?charset=utf8mb4"
        except Exception as e:
            self.app.logger.error(f"Error obteniendo dialect de Mysql. {e}")
        return self.dialect

    def create_engine(self) -> None:
        try:
            url = self.get_dialect()
            self.engine = create_engine(url, pool_recycle=3600, pool_pre_ping=True, **self.params)
        except Exception as e:
            self.app.logger.error(f"Error creando engine de Mysql. {e}")

    def get_session(self):
        session = None
        try:
            if isinstance(self.engine, type(None)):
                self.create_engine()
            session_factory = sessionmaker(bind=self.engine)
            session = scoped_session(session_factory)
        except Exception as e:
            self.app.logger.error(f"Error creando sesion de conexión para Mysql. {e}")
        finally:
            return session

    def verify_table(self, table_name, connection) -> bool:
        exists = False
        try:
            check_query = f"SELECT COUNT(*) FROM {table_name}"
            result = connection.execute(check_query)
            result = result.fetchone()[0]
            if result > 0:
                exists = True
        except Exception as e:
            self.app.logger.info(f"No se encuentra la tabla {table_name} en la BD interna. {e}")
        finally:
            return exists

    def get_action_by_identifier(self, identifier, session):
        script_name = None
        try:
            exists = session.query(Model).filter(Model.identifier == identifier).first()
            if exists is not None:
                script_name = exists.script_name
        except Exception as e:
            session.rollback()
            self.app.logger.info(f"No se encuentra el identificador {identifier} en la BD interna. {e}")
        finally:
            return script_name
