import serial
import json
import time
import os
import requests  # <-- Handlers for outbound internet requests

# --- Configuration ---
PORT = 'COM7' 
BAUD = 115200
JSON_FILE = "data.json"
LOG_FILE = "scans.json"
DATA_DIR = "scans"

# --- Cloud Storage Settings (Strategy B) ---
# TODO: Swap these placeholders with your actual jsonbin.io credentials
BIN_ID = "6a0a500d250b1311c366113f"
API_KEY = "$2a$10$aTFoV9lwVgn2HDn1W.eLhepzX8lFRJQ5FLpGZQgcUhNUoVrqREKbq" 

CLOUD_URL = f"https://api.jsonbin.io/v3/b/6a0a500d250b1311c366113f"
HEADERS = {
    "Content-Type": "application/json",
    "X-Master-Key": API_KEY
}

# Ensure historical tracking folder structure exists
if not os.path.exists(DATA_DIR):
    os.makedirs(DATA_DIR)

try:
    ser = serial.Serial(PORT, BAUD, timeout=1)
    print(f"---  MASTER BRIDGE ACTIVE (CLOUD RELAY) ---")
    print(f"Connected: {PORT} | Monitoring IR Obstacle Data Path...")
    print(f"Targeting Cloud Bin Location: {BIN_ID}")
    print(f"Waiting for 'SEND PC' input from XIAO...")
except Exception as e:
    print(f"CRITICAL ERROR: {e}")
    exit()

def update_master_index(new_filename, timestamp):
    history = []
    if os.path.exists(LOG_FILE):
        try:
            with open(LOG_FILE, "r") as f:
                history = json.load(f)
        except:
            history = []
    
    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):
    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)

def push_to_cloud(payload):
    """Sends the latest vector structure straight to your online jsonbin"""
    try:
        print("[*] Uploading matrix data packet to cloud...")
        # JSONBin uses PUT requests to completely overwrite an existing bin with new data
        response = requests.put(CLOUD_URL, json=payload, headers=HEADERS, timeout=6)
        if response.status_code == 200:
            print("[+] Cloud Update Successful! Online stream is live.")
        else:
            print(f"[-] Cloud Update Failed. Server Code: {response.status_code}")
            print(f"    Response Message: {response.text}")
    except Exception as e:
        print(f"[-] Network Pipeline Bottleneck: {e}")

while True:
    line = ser.readline().decode('utf-8', errors='ignore').strip()
    
    # Track secondary button actions asynchronously 
    if line == "NAV_BUTTON_PRESSED":
        print(f"[*] Nav Button Triggered at {time.strftime('%H:%M:%S')}")
        continue

    if line == "START_DATA":
        print("\n[!] Incoming Data Pulse Sequence Started...")
        display_ts = time.strftime("%Y-%m-%d %H:%M:%S")
        file_ts = time.strftime("%Y%m%d-%H%M%S")
        
        points_list = []
        sensor_triggered = False

        while True:
            data = ser.readline().decode('utf-8', errors='ignore').strip()
            if data == "END_DATA": 
                break
            
            if data.startswith("SCAN:"):
                try:
                    content = data.split(":")[1]
                    parts = content.split(",")
                    
                    y1_val = float(parts[2])
                    points_list.append({"x": float(parts[1]), "y": y1_val})
                    points_list.append({"x": float(parts[3]), "y": float(parts[4])})
                    
                    # If the Y extension value hits 50.0, the path was blocked
                    if y1_val >= 50.0:
                        sensor_triggered = True
                except Exception as e:
                    print(f"  > Parse Error: {e}")

        # --- PROCESS LOCAL FILES & CLOUD TRANSMISSION ---
        if len(points_list) > 0:
            status_string = "OBSTACLE DETECTED" if sensor_triggered else "PATH CLEAR"
            txt_filename = f"report_{file_ts}.txt"
            txt_path = os.path.join(DATA_DIR, txt_filename)
            
            # 1. Write the human-readable text log locally
            with open(txt_path, "w") as txt_file:
                txt_file.write(f"========================================\n")
                txt_file.write(f"           SCAN REPORT         \n")
                txt_file.write(f"========================================\n")
                txt_file.write(f"Timestamp: {display_ts}\n")
                txt_file.write(f"Hardware Module: IR Obstacle Matrix\n")
                txt_file.write(f"Sensor Output State: {status_string}\n")
                txt_file.write(f"Raw Vector Array: {points_list}\n")
                txt_file.write(f"----------------------------------------\n")
            
            # 2. Package the payload dictionary structure
            scan_json_path = os.path.join(DATA_DIR, f"scan_{file_ts}.json")
            scan_payload = {"timestamp": display_ts, "status": status_string, "points": points_list}
            
            # 3. Maintain offline backups on your local machine hard drive
            atomic_write(scan_json_path, scan_payload)
            update_master_index(scan_json_path, display_ts)
            atomic_write(JSON_FILE, scan_payload)

            print(f"--------------------------------")
            print(f"LOCAL BACKUPS SUCCESSFULLY SAVED")
            print(f"TXT LOG: {txt_path}")
            print(f"STATE:   {status_string}")
            print(f"--------------------------------")

            # 4. Fire the payload out to the cloud bin instantly over the network
            push_to_cloud(scan_payload)