import os
import pickle
import json



class database:
    def __init__(self, db_file: str, mode: bool = False, logging: bool = False):

        """
        Initializes the database handler, setting up the file path and operation mode.

        Args:
            db_file (str): The name of the file (e.g., 'data.json' or 'cache.dat').
                           The extension is used to determine the file type.
            mode (bool): If False (default), uses 'pickle' (binary) for serialization.
                         If True, uses 'json' (text) for serialization.
            logging (bool): If True, prints status messages for write and delete operations.
        """

        self.mode = mode
        self.logging = logging
        self.fileType = db_file.split('.')[1]
        self.fileName = db_file.split('.')[0]


    def WriteDatabase(self, data, cell):

        """
        Writes data to the specified key (cell) in the database file.

        The operation follows an atomic pattern:
        1. Read the existing database content.
        2. Update the dictionary with the new data for the given cell.
        3. Write the updated dictionary to a temporary file.
        4. Rename the temporary file to overwrite the original, ensuring integrity.

        Args:
            data: The value to be saved. Must be serializable by the chosen mode (pickle or json).
            cell: The key under which the data will be stored (will be converted to a string).
        """
        
        if self.logging == True:
            print(f"Writing to file '{self.fileName}.{self.fileType}'. Writing... ")

        try:
            if self.mode == False:
                try:
                    with open(f"{self.fileName}.{self.fileType}", 'rb') as file:
                        loaded_data = pickle.load(file)
                except FileNotFoundError:
                    loaded_data = {}
            elif self.mode == True:
                try:
                    with open(f"{self.fileName}.{self.fileType}", 'r', encoding='utf-8') as file:
                        loaded_data = json.load(file)
                except FileNotFoundError:
                    loaded_data = {}
                    
            loaded_data[str(cell)] = data

            if self.mode == False:
                with open(f"{self.fileName}.{self.fileType}.temp", 'wb') as file:
                    pickle.dump(loaded_data, file)

            elif self.mode == True:
                with open(f"{self.fileName}.{self.fileType}.temp", 'w', encoding='utf-8') as file:
                    json.dump(loaded_data, file)

            os.rename(f"{self.fileName}.{self.fileType}.temp", f"{self.fileName}.{self.fileType}")
                
            if self.logging == True:
                print(f"Writing to file '{self.fileName}.{self.fileType}' done! ")

        except Exception as e:
            if self.logging == True:
                print(f"An error occurred during saving: {e} ")


    def ReadDatabase(self, cell):

        """
        Reads and returns the data stored under the specified key (cell).

        Args:
            cell: The key associated with the data to retrieve.

        Returns:
            The data stored under the given key, or None if an error (like FileNotFoundError) occurs.
        """

        try:
            if self.mode == False:
                with open(f"{self.fileName}.{self.fileType}", 'rb') as file:
                    loaded_data = pickle.load(file)[str(cell)]
            elif self.mode == True:
                with open(f"{self.fileName}.{self.fileType}", 'r', encoding='utf-8') as file:
                    loaded_data = json.load(file)[str(cell)]
            return loaded_data
        
        except FileNotFoundError:
            print(f"Error: The file {self.fileName}.{self.fileType} was not found. ")
            return []
        except Exception as e:
            print(f"An error occurred during loading: {e} ")
            return []
        
        if self.logging == True:
            print(f"Database file '{self.fileName}.{self.fileType}' Reading... ")
            
            
    def ReadEntireDatabase(self):

        """
        Reads and returns the entire contents of the database file as a dictionary.

        Returns:
            A dictionary containing all key-value pairs from the database,
            or None if an error (like FileNotFoundError) occurs.
        """

        try:
            if self.mode == False:
                with open(f"{self.fileName}.{self.fileType}", 'rb') as file:
                    loaded_data = pickle.load(file)
            elif self.mode == True:
                with open(f"{self.fileName}.{self.fileType}", 'r', encoding='utf-8') as file:
                    loaded_data = json.load(file)
            return loaded_data
            
        except FileNotFoundError:
            print(f"Error: The file {self.fileName}.{self.fileType} was not found. ")
            return []
        except Exception as e:
            print(f"An error occurred during loading: {e} ")
            return []
        
        if self.logging == True:
            print(f"Database file '{self.fileName}.{self.fileType}' Reading... ")
    


    def DeleteDatabase(self):

        """
        Deletes the physical database file from the file system.
        """
        
        try:
            os.remove(f"{self.fileName}.{self.fileType}")
            if self.logging == True:
                print(f"Deleting database file '{self.fileName}'")

        except FileNotFoundError:
            print(f"Error: The file {self.fileName}.{self.fileType} was not found. ")
        except Exception as e:
            print(f"An error occurred during deleting: {e} ")

