import tkinter as tk
from tkinter import ttk
import numpy as np
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pywifi
import time
import threading

# --------------------------
# Parameters
# --------------------------
N = 400               # Number of points per network
dt = 50               # GUI update interval in ms
audio_scale = 0.02    # Amplitude of vibration for analog feel
wifi_update_interval = 1.0  # Seconds between Wi-Fi scans
max_networks = 6       # Max number of networks to display

# --------------------------
# Tkinter setup
# --------------------------
root = tk.Tk()
root.title("HDGL Wi-Fi EMF Visualizer")

# --------------------------
# Matplotlib figure
# --------------------------
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111, projection='3d')
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

# --------------------------
# Slider frame
# --------------------------
slider_frame = tk.Frame(root)
slider_frame.pack(side=tk.BOTTOM, fill=tk.X)

def make_slider(label, minv, maxv, default, row):
    tk.Label(slider_frame, text=label).grid(row=row, column=0, sticky='w')
    var = tk.DoubleVar(value=default)
    slider = tk.Scale(slider_frame, from_=minv, to=maxv, resolution=0.01,
                      orient=tk.HORIZONTAL, variable=var)
    slider.grid(row=row, column=1, sticky='we')
    return var

morph_var = make_slider("Morph (Polar→Cartesian)", 0, 1, 0, 0)
ampl_var  = make_slider("Amplitude Scale", 0, 2, 1, 1)

# --------------------------
# Lattice setup
# --------------------------
phi = (1 + np.sqrt(5)) / 2  # Golden ratio
theta = 2 * np.pi / phi
radii = np.sqrt(np.arange(N))
angles = np.arange(N) * theta
zs = np.linspace(-1,1,N)

def get_lattice(t=0, audio_mod=0):
    r = radii + audio_mod * audio_scale
    x_polar = r * np.cos(angles)
    y_polar = r * np.sin(angles)
    z_polar = zs * ampl_var.get()

    morph = morph_var.get()
    x_cart = x_polar * (1-morph) + np.linspace(-1,1,N) * morph
    y_cart = y_polar * (1-morph) + np.linspace(-1,1,N) * morph
    z_cart = z_polar * (1-morph) + np.linspace(-1,1,N) * morph

    return x_cart, y_cart, z_cart

# --------------------------
# Wi-Fi scanning
# --------------------------
wifi = pywifi.PyWiFi()
iface = wifi.interfaces()[0]

wifi_data = {}  # SSID -> signal strength
wifi_lock = threading.Lock()

def scan_wifi_loop():
    while True:
        scan_results = iface.scan_results()
        with wifi_lock:
            wifi_data.clear()
            for net in scan_results[:max_networks]:
                wifi_data[net.ssid] = net.signal
        time.sleep(wifi_update_interval)

threading.Thread(target=scan_wifi_loop, daemon=True).start()

# --------------------------
# Initial scatter points
# --------------------------
scatters = {}
colors = plt.cm.get_cmap('hsv', max_networks)

for i in range(max_networks):
    x, y, z = get_lattice()
    scatters[i] = ax.scatter(x, y, z, s=15, c=[colors(i)]*N, alpha=0.7)

ax.set_xlim(-5,5)
ax.set_ylim(-5,5)
ax.set_zlim(-2,2)

# --------------------------
# Animation update
# --------------------------
vibration_phase = np.random.rand(max_networks, N) * 2*np.pi

def update_frame():
    t = time.time()
    with wifi_lock:
        nets = list(wifi_data.keys())
        strengths = [wifi_data[ssid] for ssid in nets]

    for i, ssid in enumerate(nets):
        x, y, z = get_lattice(t)
        # Add organic vibration based on Wi-Fi signal
        vib = np.sin(t*5 + vibration_phase[i]) * strengths[i]/100
        z_vib = z + vib
        scatters[i]._offsets3d = (x, y, z_vib)

    canvas.draw_idle()
    root.after(dt, update_frame)

root.after(dt, update_frame)
root.mainloop()
