import re
import os

map_file_path = "./_obj/_map.map"


# Highly precise pattern to grab the object file at the end of a section line
# Matches strings ending in .o or .o) if it's inside an archive like libgcc.a(foo.o)
file_extractor_pattern = re.compile(r"([^\s\(\)]+\.o)\b")

discarded_files = set()
used_files = set()

# State tracking flag
current_section = None

if not os.path.exists(map_file_path):
    print(f"Error: Map file '{map_file_path}' not found.")
    exit(1)

with open(map_file_path, "r", encoding="utf-8", errors="ignore") as f:
    for line in f:
        # Detect which major section of the map file we are entering
        if "Discarded input sections" in line:
            current_section = "DISCARDED"
            continue
        elif "Linker script and memory map" in line:
            current_section = "MEMORY_MAP"
            continue
        elif "Cross Reference Table" in line or "OUTPUT(" in line:
            current_section = None
            continue

        # Parse based on the section we are currently walking through
        if current_section == "DISCARDED":
            match = file_extractor_pattern.search(line)
            if match:
                path = os.path.normpath(match.group(1).strip())
                discarded_files.add(path)

        elif current_section == "MEMORY_MAP":
            # Ensure the line contains a valid hex memory address allocation
            if "0x" in line:
                match = file_extractor_pattern.search(line)
                if match:
                    path = os.path.normpath(match.group(1).strip())
                    used_files.add(path)

# A file is truly UNUSED only if it was discarded AND never used anywhere else
truly_unused_files = discarded_files - used_files

# --- Output the Analysis ---
print(f"====================================================")
print(f" MAP FILE BREAKDOWN")
print(f"====================================================")
print(f"Active files inside firmware:  {len(used_files)}")
print(f"Unused/dead files           :  {len(truly_unused_files)}")
print(f"====================================================\n")

print(f"--- UNUSED FILES (0% footprint in binary) ---")
if truly_unused_files:
    for path in sorted(truly_unused_files):
        print(f"  {path}")
else:
    print("  None! Every compiled file has at least some code left in the binary.")

print(f"\n---  USED FILES (Has code/data inside binary) ---")
for path in sorted(used_files):
    print(f"  {path}")
