import json
from datetime import datetime
from datos.Config import ConfigManager
from datos.ConfigBase import Config
import os

configuracion = ConfigManager()

#PATH ACTUAL
path = os.path.dirname(os.path.abspath(__file__))

"""
Estructura JSON:
{
    entries:
            [
                {
                identifier: Nombre del Test
                date: Fecha de creación (Automatico)
                num_images: Número de imágenes
                config:
                    {
                        FPS: frames por segundo,
                        DIR_VIDEO: directorio del video,
                        DIR_ACT: directorio de trabajo,
                        IMAGES_FOLDER: directorio de imágenes,
                        MODEL_CAMERA: modelo de cámara,
                        DIR_OUTPUT: directorio de salida,
                        DIR_MATCHES: directorio de matches,
                        UMBRAL: umbral,
                        IMAGE_GLOBAL_WIDTH: ancho de la imagen,
                        IMAGE_GLOBAL_HEIGHT: alto de la imagen,
                        FACTOR_BRILLO: factor de brillo,
                        FACTOR_CONTRASTE: factor de contraste,
                        FACTOR_COLOR: factor de color,
                        REDUCCION_RUIDO: reducción de ruido,
                        TIPO_RUIDO: tipo de ruido,
                        FACTOR_RUIDO: factor de ruido,
                        db_file: archivo de base de datos,
                        DIR_KEYPOINTS: directorio de keypoints,
                        DIR_DATABASE: directorio de la base de datos,
                        TIPO_RECONOCIMIENTO: tipo de reconocimiento,
                        ESCALA_AABB: escala AABB,
                        FILTROS: filtros seleccionados,
                        SELECTED_MESH: malla seleccionada
                    },
                images: 
                    {
                        id_imagen: numero de keypoints,

                    },
                matches:
                    {
                        pair_id: numero de matches
                    }

                },
            ]
}
"""
class Entry:
    def __init__(self, identifier, date, num_images, images={}, matches={}):
        self.identifier = identifier
        self.date = date
        self.num_images = num_images
        self.images = images
        self.matches = matches

    def __str__(self):
        return f"Identifier: {self.identifier}, Date: {self.date}, Num_Images: {self.num_images}, Images: {self.images}, Matches: {self.matches}"
    
    def to_dict(self):
        return {
            'identifier': self.identifier,
            'date': self.date,
            'num_images': self.num_images,
            'images': self.images,
            'matches': self.matches
        }
    
    def get_identifier(self):
        return self.identifier
    
    def get_date(self):
        return self.date
    
    def get_num_images(self):
        return self.num_images
    
    def get_images(self):
        return self.images
    
    def get_matches(self):
        return self.matches
    
    def set_identifier(self, identifier):
        self.identifier = identifier

    def set_matches(self, matches):
        self.matches = matches

    def set_date(self, date):
        self.date = date

    def set_num_images(self, num_images):
        self.num_images = num_images

    def set_images(self, images):
        self.images = images
        
class Register:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls, *args, **kwargs)
            cls._instance.LOG_REGISTER = os.path.join(path, "data", "log_register.json")
            cls._instance.CONFIG_REGISTER = os.path.join(path, "data", "config_register.json")

            #si existe el documento log_register.json se carga
            if os.path.exists(cls._instance.LOG_REGISTER):
                cls._instance.read_json()
            else:
                cls._instance.create_empty_json(cls._instance.LOG_REGISTER)

            if not os.path.exists(cls._instance.CONFIG_REGISTER):
                cls._instance.create_empty_json(cls._instance.CONFIG_REGISTER)
                
            cls._instance.list_entries = []
            cls._instance.list_configs = []
            cls._instance.temp_config = Config().as_dict()
            cls._instance.temp_entry = Entry("", "", 0, {}, {})

        return cls._instance

    def read_json(self):
        # Una vez establecido el archivo JSON, se procede a leerlo
        try:
            self._instance.list_entries = []
            with open(self._instance.LOG_REGISTER, 'r') as file:
                data = json.load(file)
                
                for entry in data['entries']:
                    self._instance.list_entries.append(Entry(entry['identifier'], entry['date'], entry['num_images'], entry['images'], entry['matches']))

        except FileNotFoundError:
            return self.create_empty_json(self._instance.LOG_REGISTER)
    
    def get_path(self):
        return self._instance.LOG_REGISTER
    
    def get_path_config(self):
        return self._instance.CONFIG_REGISTER

    def create_empty_json(self, path):
        try:
            with open(path, 'w') as file:
                json.dump({'entries': []}, file, indent=4)

                return 0
            
        except Exception as e:
            return(f"Error creating the JSON file: {str(e)}")
        
    def get_media_keypoints(self, identificador):
        dato = self.read_entry(identificador)
        if dato != -1:
            total_keypoints = 0

            for key in dato.get_images():
                total_keypoints += dato.get_images()[key]

            return int(total_keypoints/dato.get_num_images()), dato.get_num_images()
            
        return -1

    def write_json(self):
        # Se revisa si esta configurado el archivo JSON
        try:
            # Se crea un diccionario con los datos de las entradas
            data = {'entries': [entry.to_dict() for entry in self._instance.list_entries]}

            # Se escribe el diccionario en el archivo JSON
            with open(self._instance.LOG_REGISTER, 'w') as file:
                json.dump(data, file, indent=4)

                return "Data recorded correctly."
            
        except FileNotFoundError:
            return "Error writing to JSON file."
        
    def write_config_json(self):
        # Se revisa si esta configurado el archivo JSON
        try:
            # Se crea un diccionario con los datos de las entradas
            
            data = {'entries': [config for config in self._instance.list_configs]}

            # Se escribe el diccionario en el archivo JSON
            with open(self._instance.CONFIG_REGISTER, 'w') as file:
                json.dump(data, file, indent=4)

            return "Data recorded correctly."
            
        except FileNotFoundError:
            return "Error writing to Configurations JSON file."

    def save_temp_entry(self):
        self._instance.list_entries.append(self._instance.temp_entry)
        self.write_json()

    def create_entry(self, identifier, num_images, data={}, matches={}):
        date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        self._instance.list_entries.append(Entry(identifier, date, num_images, data, matches))

        result = self.write_json()

        return result
    
    def create_config(self, identifier):
        
        self.temp_config["identificador"] = identifier
        
        self._instance.list_configs.append(self.temp_config)

        result = self.write_config_json()

        return result

    def read_entry(self, identifier):
        self.read_json()
        
        for entry in self._instance.list_entries:
            if entry.get_identifier() == identifier:
                self.temp_entry = entry
                return entry
            
        return -1
    
    def read_config_entry(self, identifier):
        self.read_config_json()
        
        for config in self._instance.list_configs:
            if config["identificador"] == identifier:
                self.temp_config = config
                configuracion.cargar_desde_json(config)
                return 0
            
        return -1
    
    def exists_entry(self, identifier):
        self.read_json()
        
        for entry in self._instance.list_entries:
            if entry.get_identifier() == identifier:
                return True
            
        return False
    
    def exists_entry_config(self, identifier):
        self.read_config_json()
        
        for config in self._instance.list_configs:
            if config["identificador"] == identifier:
                return True
            
        return False

    def read_entries_identifiers(self):
        self.read_json()
        identifiers = []

        # Extraer los identificadores de las entradas
        for entry in self._instance.list_entries:
            identifiers.append(entry.get_identifier())
        
        return identifiers
    
    def read_config_json(self):
        # Una vez establecido el archivo JSON, se procede a leerlo
        try:
            self._instance.list_configs = []
            with open(self._instance.CONFIG_REGISTER, 'r') as file:
                data = json.load(file)
                
                for config in data['entries']:
                    self._instance.list_configs.append(config)

        except FileNotFoundError:
            return self.create_empty_json(self._instance.CONFIG_REGISTER)

    def read_config_identifiers(self):
        self.read_config_json()
        identifiers = []

        # Extraer los identificadores de las entradas
        for config in self._instance.list_configs:
            identifiers.append(config["identificador"])
        
        return identifiers
    
    def update_entry(self, identifier, updated_entry):
        self.read_json()

        for entry in self._instance.list_entries:
            if entry.get_identifier() == identifier:
                entry = updated_entry
                
                return self.write_json()
            
        return "Entrada no encontrada"

    def delete_entry(self, identifier):
        self.read_json()
        
        for entry in self._instance.list_entries:
            if entry.get_identifier() == identifier:
                self._instance.list_entries.remove(entry)
                
                return self.write_json()
            
        return "Entrada no encontrada"
    
    def delete_entry_config(self, identifier):
        self.read_config_json()
        
        for config in self._instance.list_configs:
            if config["identificador"] == identifier:
                self._instance.list_configs.remove(config)
                return self.write_config_json()
            
        return "Entry not found."
    
    def append_config(self, key, value):
        self._instance.temp_config[key] = value