import numpy as np
import pandas as pd
import plotly.graph_objects as go
from sklearn.linear_model import LinearRegression

# -------------------------------
# Synthetic dataset (replace with your experimental CSV)
# Columns: freq, const, phi, phi_inv, fib, dyad, prime_log, omega, alpha, beta, eta, zeta
# -------------------------------
N = 150
frequencies = np.linspace(100, 1000, N)
X = np.vstack([
    frequencies,
    frequencies**2,
    np.sin(frequencies/100),
    np.cos(frequencies/200),
    np.power(1.618, frequencies/500),
    np.sqrt(frequencies),
    np.log1p(frequencies)
]).T
Y = np.vstack([
    3*np.sin(frequencies/200)+0.1*np.random.randn(N),
    6*np.sin(frequencies/400)+0.1*np.random.randn(N),
    2*np.cos(frequencies/300)+0.05*np.random.randn(N),
    3*np.cos(frequencies/350)+0.05*np.random.randn(N)
]).T

# Fit linear model (T matrix)
model = LinearRegression().fit(X, Y)

# Function to predict cymatic params from frequency
def predict_params(f):
    features = np.array([
        f,
        f**2,
        np.sin(f/100),
        np.cos(f/200),
        np.power(1.618, f/500),
        np.sqrt(f),
        np.log1p(f)
    ]).reshape(1,-1)
    pred = model.predict(features)[0]
    return dict(alpha=abs(pred[0]), beta=abs(pred[1]), eta=abs(pred[2]), zeta=abs(pred[3]))

# -------------------------------
# Generate interactive sweep
# -------------------------------
Nx, Ny = 100, 100
x = np.linspace(0, 1, Nx)
y = np.linspace(0, 1, Ny)
Xg, Yg = np.meshgrid(x, y)

frames = []
for f in np.linspace(100, 1000, 50):  # 50 frequency steps
    p = predict_params(f)
    Z = np.sin(p['alpha']*np.pi*Xg) * np.sin(p['beta']*np.pi*Yg) + p['eta']*np.cos(p['zeta']*np.pi*(Xg+Yg))
    frames.append(go.Frame(data=[go.Surface(z=Z, x=Xg, y=Yg, colorscale='Viridis', showscale=False)], name=f'{f:.1f} Hz'))

# Initial frame
Z0 = np.sin(p['alpha']*np.pi*Xg) * np.sin(p['beta']*np.pi*Yg) + p['eta']*np.cos(p['zeta']*np.pi*(Xg+Yg))

fig = go.Figure(
    data=[go.Surface(z=Z0, x=Xg, y=Yg, colorscale='Viridis', showscale=False)],
    layout=go.Layout(
        title='Interactive Cymatic Sweep',
        scene=dict(zaxis=dict(range=[-5,5])),
        updatemenus=[dict(type='buttons', showactive=False, y=1, x=1.1, xanchor='right', yanchor='top',
                          pad=dict(t=0, r=10), buttons=[dict(label='Play', method='animate', args=[None, dict(frame=dict(duration=200, redraw=True), fromcurrent=True, transition=dict(duration=0))]),
                                                         dict(label='Pause', method='animate', args=[[None], dict(frame=dict(duration=0, redraw=False), mode='immediate', transition=dict(duration=0))])])]
    ),
    frames=frames
)

fig.show()
