from typing import Any, Dict
import importlib.util

from app.main.engine.action.ActionInterface import ActionInterface

# RELACION DE IDENTIFICADOR DE ACCION Y NOMBRE DE CLASE
relation_classname_identifier = {
    "match-and-exclude-records-actions": "MatchAndExcludeRecordsAction"
}

# CONFIGURACION DE SESION DE SPARK
MASTER = "local[*]"
DRIVER_MEMORY = "4g"
EXECUTOR_MEMORY = "4g"
MYSQL_JAR_PATH = "jars/mysql-connector-java-8.0.30.jar"


class MatchAndExcludeRecordsAction(ActionInterface):

    library_required = "pyspark"
    version_required = "3.4.0"

    def __init__(self, app) -> None:
        super().__init__(app)
        self.max_combinations = None
        self.timeout = None
        self.exclude_pivot = None
        self.pivot_params = None
        self.ctp_params = None
        self.config_params = ["max-records-per-combinations", "max-timeout-per-combinations", "exclude-entity-pivot"]

    def parser(self, descriptor: Dict[str, Any]):
        # Validar si pyspark y su versión está instalada
        pyspark_lib = importlib.util.find_spec(self.library_required)
        if pyspark_lib is None:
            raise ImportError(f"Librería requerida *{self.library_required}* no instalada")
        import pyspark
        version = pyspark.__version__
        if version != self.version_required:
            raise ImportError(f"Versión requerida no instalada. Requerida: {self.version_required}. Instalada: {version}")

        # Validación de parámetros de entrada
        entity_config_params = ["tablename", "id-column", "amount-column", "columns-group", "columns-transaction"]

        if "config-params" not in descriptor.keys():
            raise ReferenceError(f"Parámetro *params-input* no definido en descriptor")

        configs = descriptor["config-params"]
        for param in self.config_params:
            if param not in configs.keys():
                raise ReferenceError(f"Parámetro *{param}* no definido en configuracion")

        if "params-input" not in descriptor.keys():
            raise ReferenceError(f"Parámetro *params-input* no definido en descriptor")

        params_input = descriptor["params-input"]
        if "pivot-config" not in params_input.keys() or "counterpart-config" not in params_input.keys():
            raise ReferenceError(f"Pivot o Contraparte no definidos en descriptor")

        pivot_params, ctp_params = params_input["pivot-config"], params_input["counterpart-config"]
        for param in entity_config_params:
            if param not in pivot_params.keys() or param not in ctp_params.keys():
                raise ReferenceError(f"Parámetro *{param}* no encontrado en pivot o contraparte")

        self.max_combinations = configs["max-records-per-combinations"]
        self.timeout = configs["max-timeout-per-combinations"]
        self.exclude_pivot = configs["exclude-entity-pivot"]
        self.pivot_params = pivot_params
        self.ctp_params = ctp_params

    def process(self, source_obj):
        # Inicializar la sesion de Spark
        session = self.createSession()

        # Traer la data desde BD tanto pivot como contraparte
        pivot_table, ctp_table = self.pivot_params["tablename"], self.ctp_params["tablename"]
        jdbc_conn = source_obj.create_spark_connection()
        jdbc_url = jdbc_conn["url"]
        jdbc_properties = jdbc_conn["properties"]
        print(jdbc_url, jdbc_properties)
        pivot_df = session.read.jdbc(url=jdbc_url, table=pivot_table, properties=jdbc_properties)

    def response(self):
        print("Llegue al response3")

    def createSession(self, name: str = "app_engine_spark"):
        try:
            from pyspark.sql import SparkSession
            session = SparkSession.builder.master(MASTER) \
                .appName(name) \
                .config("spark.jars", MYSQL_JAR_PATH) \
                .config("spark.executor.extraClassPath", MYSQL_JAR_PATH) \
                .config("spark.driver.extraClassPath", MYSQL_JAR_PATH) \
                .config("spark.driver.memory", DRIVER_MEMORY) \
                .config("spark.executor.memory", EXECUTOR_MEMORY) \
                .getOrCreate()
            self.app.logger.info(f"Sesión creada exitosamente")
            return session
        except Exception as e:
            raise Exception(f"Error creando sesion Spark. {e}")


















