import serial
import json
import time
import ezdxf
import os

# --- Configuration ---
PORT = 'COM7' 
BAUD = 115200
TINE_PITCH = 3.0  # 3mm between tines
MAX_TRAVEL = 50.0 # 50mm max extension
JSON_FILE = "data.json"
LOG_FILE = "scans.json"
DATA_DIR = "scans"

# Ensure the subfolder for historical scans exists
if not os.path.exists(DATA_DIR):
    os.makedirs(DATA_DIR)

try:
    # IMPORTANT: Close Arduino Serial Monitor before running this
    ser = serial.Serial(PORT, BAUD, timeout=1)
    print(f"--- RESURRECT MASTER BRIDGE ACTIVE ---")
    print(f"Connected: {PORT} | Pitch: {TINE_PITCH}mm | Max Travel: {MAX_TRAVEL}mm")
    print(f"Waiting for 'SEND PC' from XIAO...")
except Exception as e:
    print(f"CRITICAL ERROR: {e}")
    exit()

def update_master_index(new_filename, timestamp):
    """Adds the new scan metadata to the top of the history index."""
    history = []
    if os.path.exists(LOG_FILE):
        try:
            with open(LOG_FILE, "r") as f:
                history = json.load(f)
        except:
            history = []
    
    # Insert newest scan at the beginning
    history.insert(0, {"timestamp": timestamp, "file": new_filename})
    
    with open(LOG_FILE, "w") as f:
        json.dump(history, f, indent=2)

def atomic_write(filename, data):
    """Writes to a temp file then renames to prevent reading empty files."""
    temp_name = "temp_write.json"
    with open(temp_name, "w") as f:
        json.dump(data, f, indent=2)
        f.flush()
        os.fsync(f.fileno())
    
    if os.path.exists(filename):
        os.remove(filename)
    os.rename(temp_name, filename)

while True:
    line = ser.readline().decode('utf-8', errors='ignore').strip()
    
    if line == "START_DATA":
        print("\n[!] Incoming Scan Sequence Started...")
        # Create unique timestamps for filenames and display
        display_ts = time.strftime("%Y-%m-%d %H:%M:%S")
        file_ts = time.strftime("%Y%m%d-%H%M%S")
        
        points_list = []
        doc = ezdxf.new('R2010')
        msp = doc.modelspace()
        lines_processed = 0

        while True:
            data = ser.readline().decode('utf-8', errors='ignore').strip()
            
            if data == "END_DATA": 
                break
            
            if data.startswith("SCAN:"):
                try:
                    # Expected format from Arduino: SCAN:Index,X1,Y1,X2,Y2
                    content = data.split(":")[1]
                    parts = content.split(",")
                    
                    p1 = (float(parts[1]), float(parts[2]))
                    p2 = (float(parts[3]), float(parts[4]))

                    # 1. Add to CAD DXF
                    msp.add_line(p1, p2)
                    
                    # 2. Add to Web Data List
                    points_list.append({"x": p1[0], "y": p1[1]})
                    points_list.append({"x": p2[0], "y": p2[1]})
                    
                    lines_processed += 1
                    print(f"  > Processed Segment {parts[0]}: {p1[1]}mm to {p2[1]}mm")
                except Exception as e:
                    print(f"  > Parse Error on line '{data}': {e}")

        # --- FINALIZING SCAN ---
        if len(points_list) > 0:
            # Save the engineering DXF
            dxf_path = f"contour_{file_ts}.dxf"
            doc.saveas(dxf_path)
            
            # Save the unique JSON file in the scans folder
            scan_json_path = os.path.join(DATA_DIR, f"scan_{file_ts}.json")
            scan_payload = {"timestamp": display_ts, "points": points_list}
            atomic_write(scan_json_path, scan_payload)
            
            # Update the Master Log for the Sidebar
            update_master_index(scan_json_path, display_ts)
            
            # Update the 'latest' file for the Live View
            atomic_write(JSON_FILE, scan_payload)

            print(f"--------------------------------")
            print(f"STATUS: SUCCESS")
            print(f"DXF: {dxf_path}")
            print(f"HISTORY: {scan_json_path}")
            print(f"TOTAL POINTS: {len(points_list)}")
            print(f"--------------------------------")
        else:
            print("WARNING: Data block received but no valid points found.")