#!/usr/bin/env python3
"""
Synchronous 3D Visualization - No Animation Framework
Direct rendering loop for guaranteed window display
"""

import re
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from collections import deque
import time

LOG_FILE = "../logs/peer1.log"

class Monitor:
    def __init__(self):
        self.positions = deque(maxlen=500)
        self.last_pos = 0
        self.omega = 0
        self.evol = 0
        self.skip = 0

    def update(self):
        try:
            with open(LOG_FILE, 'r', encoding='utf-8', errors='ignore') as f:
                f.seek(self.last_pos)
                lines = f.readlines()
                self.last_pos = f.tell()

                dims = {}
                for line in lines:
                    if 'Ω:' in line and 'Evolution:' in line:
                        try:
                            parts = line.split('│')
                            self.evol = int(parts[0].split(':')[1].strip())
                            self.omega = float(parts[2].split(':')[1].strip())
                        except:
                            pass

                    for i in range(1, 9):
                        if f'  D{i}:' in line:
                            try:
                                dims[i-1] = float(line.split(':')[1].split('[')[0].strip())
                            except:
                                pass

                    if len(dims) == 8:
                        self.skip += 1
                        if self.skip % 5 == 0:  # Every 5th
                            self.positions.append(tuple(dims[i] for i in range(8)))
                        dims = {}
        except:
            pass

def main():
    print("\n" + "="*70)
    print("  🎨 SYNCHRONOUS 3D CHROMATIC VISUALIZATION")
    print("  Direct rendering - no animation framework")
    print("="*70)

    monitor = Monitor()

    # Create figure with interactive mode
    plt.ion()
    fig = plt.figure(figsize=(12, 9))
    ax = fig.add_subplot(111, projection='3d')

    # Styling
    fig.patch.set_facecolor('#050510')
    ax.set_facecolor('#0a0a1a')
    ax.set_xlabel('X (D1+D8)', color='white', fontsize=10)
    ax.set_ylabel('Y (D3+D6)', color='white', fontsize=10)
    ax.set_zlabel('Z (D4+D5)', color='white', fontsize=10)
    ax.tick_params(colors='cyan', labelsize=8)
    ax.grid(True, alpha=0.1, color='cyan')

    # Force window to show
    fig.show()
    plt.pause(0.5)  # Give it time to appear

    print("\n✅ Window should be visible NOW!")
    print("   If not visible, check Alt+Tab or taskbar")
    print("   Press Ctrl+C in terminal to stop\n")

    frame = 0
    azim = 0

    try:
        while plt.fignum_exists(fig.number):
            # Update data
            monitor.update()

            if len(monitor.positions) >= 10:
                # Convert and process
                pos_list = list(monitor.positions)
                arr = np.array(pos_list, dtype=np.float64)  # Use float64 to avoid overflow

                # Safe log
                arr = np.log10(np.maximum(np.abs(arr), 1e-200))

                # Normalize safely
                for i in range(8):
                    col = arr[:, i]
                    min_val, max_val = col.min(), col.max()
                    if max_val > min_val and np.isfinite(min_val) and np.isfinite(max_val):
                        arr[:, i] = (col - min_val) / (max_val - min_val)
                    else:
                        arr[:, i] = 0.5

                # Project to 3D
                x = arr[:, 0] * 0.6 + arr[:, 7] * 0.4
                y = arr[:, 2] * 0.5 + arr[:, 5] * 0.5
                z = arr[:, 4] * 0.5 + arr[:, 3] * 0.5

                # Remove old plot and create new
                ax.clear()

                # Re-apply styling after clear
                ax.set_facecolor('#0a0a1a')
                ax.set_xlabel('X (D1+D8)', color='white', fontsize=10)
                ax.set_ylabel('Y (D3+D6)', color='white', fontsize=10)
                ax.set_zlabel('Z (D4+D5)', color='white', fontsize=10)
                ax.set_xlim(0, 1)
                ax.set_ylim(0, 1)
                ax.set_zlim(0, 1)
                ax.tick_params(colors='cyan', labelsize=8)
                ax.grid(True, alpha=0.1, color='cyan')

                # Plot with color gradient
                colors = plt.cm.plasma(np.linspace(0, 1, len(x)))
                ax.scatter(x, y, z, c=colors, s=3, alpha=0.7)

                # Title
                omega_status = "SAT" if monitor.omega >= 999 else "GROW"
                ax.set_title(f'8D Chromatic | Ω={monitor.omega:.0f} ({omega_status}) | E={monitor.evol//1000000}M | {len(pos_list)} pts',
                           color='cyan', fontsize=11, pad=10)

                # Rotate
                azim = (azim + 1) % 360
                ax.view_init(elev=25, azim=azim)

                # Force update
                fig.canvas.draw()
                fig.canvas.flush_events()

                if frame % 30 == 0:
                    print(f"Frame {frame}: {len(pos_list)} points | Ω={monitor.omega:.0f} | Azim={azim}°")
            else:
                # Waiting for data
                if frame % 30 == 0:
                    print(f"Waiting for data... ({len(monitor.positions)} points so far)")

            frame += 1
            time.sleep(0.15)  # ~7 FPS

    except KeyboardInterrupt:
        print("\n\n✅ Stopped by user")
    finally:
        plt.close('all')

if __name__ == "__main__":
    main()
