"""Script to generate a binary file for ESP8266 EEPROM"""
from typing import Any
import struct

class EEPROMBuilder:
    def __init__(self, size=1024) -> None:
        self.size = size
        self.entries = []

    def add(self, key: str, value: Any, format_char: str, start_address: int) -> None:
        bindata = struct.pack(format_char, value)
        self.entries.append({
            "key": key,
            "value": value,
            "format_char": format_char,
            "starting_address": start_address,
            "bindata": bindata,
            "size": len(bindata)
        })
        # print(f"Added {key} to EEPROM!")

    def generate_binary_file(self, filename: str) -> bytes:
        """Generates the EEPROM binary file that will be flashed in ESP8266"""
        # Sort the entire entries on starting_address
        # Go over each entry and check if they are not overlapping
        # starting_adress + size should not be greater than the next starting address
        bindata = bytearray([0x0] * self.size)

        if len(self.entries) == 0:
            print("No EEPROM entries were specified!")
            return bytes(bindata)
        
        prev_key = self.entries[0]["key"]
        prev_ending_address = self.entries[0]["starting_address"] + self.entries[0]["size"]
        for index, entry in enumerate(self.entries):
            
            # skip the first entry
            if index == 0:
                continue
            
            # check if prev key's ending address is greater than next keys starting address
            # it means that they are overlapping
            if prev_ending_address > entry["starting_address"]:
                raise Exception(f"The key '{prev_key}' is overlapping into the memory region for '{entry['key']}'. Change starting address and size and try again.")
            
            else:
                prev_ending_address = entry["starting_address"] + entry["size"]
                prev_key = entry["key"]


        for entry in self.entries:
            starting_address = entry['starting_address']
            content_length = entry['size']
            bindata[starting_address : starting_address + content_length] = entry["bindata"]
        
        with open(filename, "wb") as f:
            f.write(bindata)

        return bytes(bindata)
    
    def generate_header_file(self, filename: str):
        root = "// This file is automatically generated from inject_build_info.py file\n// during the build process. DO NOT EDIT IT MANUALLY!\n\n"
        template = "#ifndef {key}_EEPROM_START_ADDR\n\t#define {key}_EEPROM_START_ADDR {start_address}\n#endif\n\n"
        for entry in self.entries:
            root += template.format(key=entry["key"], start_address=entry["starting_address"])
        
        with open(filename, "w") as f:
            f.write(root)

