import uuid
from typing import Dict, Any
import os
import shutil
from enum import Enum
# from pyspark.sql import SparkSession
import json
from app.main.engine.util.Timezone import Timezone

# from config import Config as cfg
from app.main.engine.enum.StatusEnum import StatusEnum
from app.main.engine.enum.SufixEnum import SufixEnum
from app.main.engine.enum.FixedFieldsEnum import FixedFieldsEnum
from app.main.engine.enum.DescResponseEnum import DescResponseEnum
from app.main.engine.models.ResultMode import ResultModel

class Utils:

    def __init__(self, app) -> None:
        self.app = app
        self.timezone = Timezone(app)
    # def createSession(self, name: str = "app_engine_spark") -> SparkSession:
    #     session = None
    #     try:
    #         spark_master = "local["+str(cfg.spark_cores)+"]"
    #         total_mem = cfg.spark_mem
    #         driver_mem = str(int(total_mem / 2)) + 'g'
    #         executor_mem = str(int(total_mem / 2)) + 'g'
    #         jars = list(cfg.spark_jars.values())
    #         jars = ",".join(jars)
    #         session = SparkSession.builder.master(spark_master) \
    #             .appName(name) \
    #             .config("spark.jars", jars) \
    #             .config("spark.executor.extraClassPath", jars) \
    #             .config("spark.driver.extraClassPath", jars) \
    #             .config("spark.driver.memory", driver_mem) \
    #             .config("spark.executor.memory", executor_mem) \
    #             .getOrCreate()
    #
    #     except Exception as e:
    #         self.app.logger.error(f"Error creando sesion Spark. {e}")
    #     finally:
    #         return session

    def create_temp_file(self) -> str:
        fullpath = None
        try:
            dir_name = str(uuid.uuid4())
            path_dir = "/tmp/" + dir_name
            os.mkdir(path_dir)
            filename = str(uuid.uuid4()) + ".csv"
            fullpath = path_dir + "/" + filename
            open(fullpath, mode='a').close()
        except Exception as e:
            self.app.logger.error(f"Error creando directorio temporal.{e}")
        finally:
            return fullpath

    def delete_temp_dir(self, module_name: str) -> bool:
        drop = False
        try:
            if os.path.exists(module_name):
                directory = os.path.dirname(module_name)
                shutil.rmtree(directory, ignore_errors=True)
                self.app.logger.debug(f"directorio borrado: {module_name}")
        except Exception as e:
            raise AssertionError(f"Error borrando modulo temporal. {e}")
        finally:
            return drop

    def create_response(self, codeEnum: Enum, detail: str = "") -> Dict[str, Any]:
        response = {"statusCode": codeEnum.value}

        if codeEnum.value == StatusEnum.SUCCESS.value:
            response.update({'status': StatusEnum.SUCCESS.name.lower(), 'path': detail})
        else:
            description = DescResponseEnum[codeEnum.name].value
            response.update({'status': StatusEnum.ERROR.name.lower(), 'message': description,
                             'detail': detail})
        return response

    def get_script_module(self, action_module: str) -> Dict[str, Any]:
        response = {}
        try:
            pass
        except Exception as e:
            self.app.logger.error(f"Error obteniendo el script del proveedor desde S3. {e}")
            response["status"] = StatusEnum.ERROR
            response["message"] = str(e)
        finally:
            return response

    def create_result(self, data, descriptor):
        result = []
        response = {}
        try:
            exclude_pivot = descriptor["config-params"]["exclude-entity-pivot"]
            group_pivot = descriptor["params-input"]["pivot-config"]["columns-group"]

            transaction_pivot = descriptor["params-input"]["pivot-config"]["columns-transaction"]
            group_counterpart = descriptor["params-input"]["counterpart-config"]["columns-group"]

            transaction_counterpart = descriptor["params-input"]["counterpart-config"]["columns-transaction"]
            sufijo_PVT = SufixEnum.PIVOT.value
            sufijo_CTP = SufixEnum.COUNTERPART.value

            transaction_pivot_match = [sufijo_PVT + item if item == transaction_counterpart[index] else item for
                                       index, item in
                                       enumerate(transaction_pivot)]
            transaction_counterpart_match = [sufijo_CTP + item if item == transaction_pivot[index] else item for
                                             index, item in
                                             enumerate(transaction_counterpart)]

            group_pivot_match = [sufijo_PVT + item if item == group_counterpart[index] else item for index, item in
                                 enumerate(group_pivot)]
            group_counterpart_match = [sufijo_CTP + item if item == group_pivot[index] else item for index, item in
                                       enumerate(group_counterpart)]
            used_list = transaction_counterpart_match if exclude_pivot else transaction_pivot_match
            for i in data.collect():
                input_data = {}
                key_transaction = None
                key_group_pivot = None
                key_group_counterpart = None
                for element in used_list:
                    if key_transaction is None:
                        key_transaction = i[element]
                    else:
                        key_transaction = key_transaction + "-" + str(i[element])
                for element_g in group_pivot_match:
                    if key_group_pivot is None:
                        key_group_pivot = str(i[element_g])
                    else:
                        key_group_pivot = key_group_pivot + "-" + str(i[element_g])
                for element_c in group_counterpart_match:
                    if key_group_counterpart is None:
                        key_group_counterpart = str(i[element_c])
                    else:
                        key_group_counterpart = key_group_counterpart + "-" + str(i[element_c])
                input_data["key-transaction"] = str(key_transaction)
                input_data["key-group-pivot"] = str(key_group_pivot)
                input_data["key-group-counterpart"] = str(key_group_counterpart)
                input_data["list-ids-pivot"] = str(i[FixedFieldsEnum.INTER_PIVOT_ID.value])
                input_data["list-ids-counterpart"] = str(i[FixedFieldsEnum.INTER_CTP_ID.value])
                input_data["exclude-ids"] = str(i[FixedFieldsEnum.LISTA_DIFF.value])
                input_data["difference-amount"] = str(i[FixedFieldsEnum.DIFF.value])
                result.append(input_data)
            response['status'] = StatusEnum.SUCCESS.value
            response["detail"] = result
        except Exception as e:
            self.app.logger.error(f"Error obteniendo al crear el diccionario de resultados. {e}")
            response["status"] = StatusEnum.ERROR
            response["message"] = str(e)
        finally:
            return response

    def save_result(self, result, descriptor, session):
        response = {}
        try:
            d1 = self.timezone.datetime_by_tzone()

            result_json = json.dumps(result)
            result_obj = ResultModel(
                ID= None,
                ACTION_ID=descriptor["idScript"],
                ID_PROCESS=descriptor["idProcess"],
                CREATE_DATE= d1,
                KEY=FixedFieldsEnum.MATCH_RECORDS.value,
                RESULT_JSON=result_json
            )
            session.add(result_obj)
            session.commit()
            response['status'] = StatusEnum.SUCCESS.value
        except Exception as e:
            session.rollback()
            response["status"] = StatusEnum.ERROR
            response["message"] = str(e)
            self.app.logger.error(f"Error al guardar registro en la base de datos {e}")
        finally:
            session.close()
            return response
