#!/usr/bin/env python3
"""
Skiss Black Hole Accuracy Control Dashboard - Curses Version (v2)
Matches HTML logic precisely, with flicker-free max speed and responsive input.
"""

import sys
import time
import math
import random
import curses

# ---------- Global simulation state ----------
spin = 0.68
resonance = 0.52
entanglement = 0.44
comet_coherence = 0.27
skiss_noise = False
auto_stabilize = False

# Derived metrics
accuracy = 0.0
divergence = 0.0
pi_checksum = 0.0
e_checksum = 0.0
skiss_level = 0.0
traceability = 0.0
jet_angle = 0.0
crystal_consensus = 0.82
resonance_active = False
hawking_mod = 1.0

running = True
command_input = ""
last_status = "System Ready"

def compute_metrics():
    global spin, resonance, entanglement, comet_coherence
    global accuracy, divergence, pi_checksum, e_checksum, skiss_level, traceability, jet_angle, crystal_consensus
    global resonance_active, hawking_mod
    
    # 1. Automatic Stabilization (if enabled)
    if auto_stabilize:
        spin = spin * 0.98 + 0.82 * 0.02
        resonance = resonance * 0.98 + 0.68 * 0.02
        entanglement = entanglement * 0.98 + 0.71 * 0.02
        comet_coherence = comet_coherence * 0.98 + 0.33 * 0.02

    # 2. Noise / Path Erasure
    # Manual Noise (Random Walk)
    if skiss_noise:
        spin = max(0.0, min(1.0, spin + (random.random() - 0.5) * 0.012))
        resonance = max(0.0, min(1.0, resonance + (random.random() - 0.5) * 0.01))
        entanglement = max(0.0, min(1.0, entanglement + (random.random() - 0.5) * 0.008))
    
    # Automatic Path Erasure (if divergence is critical)
    if divergence > 0.37:
        intensity = (divergence - 0.37) * 0.05
        spin = max(0.0, min(1.0, spin + (random.random() - 0.5) * intensity))
        resonance = max(0.0, min(1.0, resonance + (random.random() - 0.5) * intensity))

    # Core Logic from HTML
    resonance_match = 1.0 - abs(resonance - 0.618)
    spin_factor = spin * (1 + resonance_match) / 2
    accuracy_base = (spin_factor * entanglement) * (1 + comet_coherence * 0.4)
    
    # Baseline accuracy
    acc = min(0.98, max(0.02, accuracy_base * 0.9 + 0.05))
    # Dynamic oscillation
    accuracy = acc * (0.97 + 0.06 * math.sin(time.time() * 3.0))
    accuracy = min(0.995, max(0.01, accuracy))

    # Checksum Divergence
    pi_checksum = min(0.98, max(0.12, 0.55 + (1 - accuracy) * 0.45 - (resonance_match * 0.2)))
    e_checksum = min(0.92, max(0.2, 0.618 + (1 - accuracy) * 0.4 - (entanglement * 0.2)))
    
    div_pi = abs(pi_checksum - 0.55)
    div_e = abs(e_checksum - 0.618)
    divergence = min(0.95, (div_pi * 0.7 + div_e * 0.3) * 1.2)

    # Path Erasure Logic
    if divergence > 0.37:
        skiss_level = min(0.99, skiss_level + 0.008)
    else:
        skiss_level = max(0.05, skiss_level - 0.003)
        
    traceability = max(0.05, 1.0 - skiss_level * 1.2)
    jet_angle = (spin * 360 + (resonance_match * 45)) % 360
    
    # Resonance status
    resonance_active = (resonance_match > 0.55)
    hawking_mod = 0.8 + accuracy * 0.6
    
    consensus_raw = 0.65 + accuracy * 0.35 - divergence * 0.5
    crystal_consensus = min(0.98, max(0.4, consensus_raw))

def get_black_hole_art():
    jet_char = "⤴" if 45 < jet_angle < 135 else "⤵" if 225 < jet_angle < 315 else "→" if jet_angle < 90 else "←"
    spin_dir = "↻" if spin > 0.5 else "↺"
    return [
        "                     .-''-.",
        "                   .'      '.",
        "                  /   O    O  \\",
        "                 :   '--'    :",
        "                 |    .-.    |",
        "                 :  (     )  :   jet direction: " + jet_char + f" {jet_angle:.0f}°",
        "                  \\  `---'  /",
        "                   '._____.'",
        "                     `---`",
        f"   Spin vector: {spin_dir}  |  Coherence: {accuracy*100:.1f}%"
    ]

def draw_slider(label, value, selected=False, width=30):
    prefix = "▶ " if selected else "  "
    filled = int(value * width)
    bar = "█" * filled + "░" * (width - filled)
    return f"{prefix}{label:12} [{bar}] {value:.3f}"

def main_loop(stdscr):
    global spin, resonance, entanglement, comet_coherence, skiss_noise, auto_stabilize, running, command_input, last_status
    
    # Setup curses
    curses.curs_set(1)
    stdscr.timeout(10) # Wait 10ms for input, then continue loop (~100 FPS max)
    curses.start_color()
    curses.use_default_colors()
    
    # Colors
    curses.init_pair(1, curses.COLOR_CYAN, -1)
    curses.init_pair(2, curses.COLOR_YELLOW, -1)
    curses.init_pair(3, curses.COLOR_GREEN, -1)
    curses.init_pair(4, curses.COLOR_MAGENTA, -1)
    curses.init_pair(5, curses.COLOR_RED, -1)
    curses.init_pair(6, curses.COLOR_BLUE, -1)

    selected_idx = 0
    controls = ["Spin Lattice", "Resonance", "Entanglement", "Comet Coher"]

    def safe_addstr(y, x, s, attr=0):
        try:
            h, w = stdscr.getmaxyx()
            if y < h and x < w:
                stdscr.addstr(y, x, s[:max(0, w-x-1)], attr)
        except curses.error:
            pass

    while running:
        compute_metrics()
        
        stdscr.erase()
        h, w = stdscr.getmaxyx()
        
        # Header
        safe_addstr(0, 0, "═" * min(w-1, 75), curses.color_pair(1))
        safe_addstr(1, 0, "⚫ SKISS BLACK HOLE · ACCURACY CONTROL DASHBOARD", curses.color_pair(2) | curses.A_BOLD)
        safe_addstr(2, 0, "═" * min(w-1, 75), curses.color_pair(1))
        
        # Art
        art = get_black_hole_art()
        for i, line in enumerate(art):
            safe_addstr(4 + i, 0, line)
            
        # Metrics
        safe_addstr(15, 0, "🎯 REAL-TIME ACCURACY", curses.color_pair(3) | curses.A_BOLD)
        
        acc_bar_width = int(accuracy * min(w-40, 40))
        acc_text = f"   Accuracy: {accuracy:.4f} bits/Planck   "
        safe_addstr(16, 0, acc_text + "█" * acc_bar_width, curses.color_pair(3))
        
        safe_addstr(17, 0, f"   π-checksum: {pi_checksum:.4f}   |   e-checksum: {e_checksum:.4f}", curses.color_pair(3))
        safe_addstr(18, 0, f"   Divergence D: {divergence:.4f}   ", curses.color_pair(3))
        
        if divergence > 0.37:
            safe_addstr(18, 30, "⚠️  CRITICAL DIVERGENCE", curses.color_pair(5) | curses.A_BLINK)
        else:
            safe_addstr(18, 30, "✅ Below threshold", curses.color_pair(3))
        
        # Controls
        safe_addstr(20, 0, "🌀 ATOM PATTERN CONTROLS (Arrows to tune, Enter to type)", curses.color_pair(4) | curses.A_BOLD)
        safe_addstr(21, 0, draw_slider("Spin Lattice", spin, selected_idx == 0), curses.color_pair(4))
        safe_addstr(22, 0, draw_slider("Resonance", resonance, selected_idx == 1), curses.color_pair(4))
        safe_addstr(23, 0, draw_slider("Entanglement", entanglement, selected_idx == 2), curses.color_pair(4))
        safe_addstr(24, 0, draw_slider("Comet Coher", comet_coherence, selected_idx == 3), curses.color_pair(4))
        
        # System State
        safe_addstr(26, 0, f"   Skiss Erasure: {skiss_level*100:.1f}%  |  Traceability: {traceability:.3f}  |  Consensus: {crystal_consensus*100:.0f}%", curses.color_pair(6))
        
        res_text = "⚡ RESONANT" if resonance_active else "🔴 DETUNED"
        safe_addstr(27, 0, f"   Status: {res_text}  |  Hawking Mod: {hawking_mod:.2f}x", curses.color_pair(6))

        # Footer / Input
        footer_start = max(29, h - 4)
        safe_addstr(footer_start, 0, "═" * min(w-1, 75), curses.color_pair(1))
        
        auto_text = "[AUTO-STABILIZE ON]" if auto_stabilize else "[AUTO OFF]"
        safe_addstr(footer_start + 1, 0, f"{auto_text} | Commands: [a]uto | [n]oise | [r]eset | [q]uit", curses.A_DIM)
        safe_addstr(footer_start + 2, 0, f"[{last_status}]", curses.color_pair(2))
        safe_addstr(footer_start + 3, 0, f"> {command_input}", curses.color_pair(2) | curses.A_BOLD)
        
        stdscr.refresh()
        
        ch = stdscr.getch()
        if ch != -1:
            if ch == curses.KEY_UP:
                selected_idx = (selected_idx - 1) % 4
            elif ch == curses.KEY_DOWN:
                selected_idx = (selected_idx + 1) % 4
            elif ch == curses.KEY_LEFT:
                val = [spin, resonance, entanglement, comet_coherence][selected_idx]
                val = max(0.0, val - 0.01)
                if selected_idx == 0: spin = val
                elif selected_idx == 1: resonance = val
                elif selected_idx == 2: entanglement = val
                elif selected_idx == 3: comet_coherence = val
                last_status = f"{controls[selected_idx]} tuned to {val:.3f}"
                auto_stabilize = False # Manual override
            elif ch == curses.KEY_RIGHT:
                val = [spin, resonance, entanglement, comet_coherence][selected_idx]
                val = min(1.0, val + 0.01)
                if selected_idx == 0: spin = val
                elif selected_idx == 1: resonance = val
                elif selected_idx == 2: entanglement = val
                elif selected_idx == 3: comet_coherence = val
                last_status = f"{controls[selected_idx]} tuned to {val:.3f}"
                auto_stabilize = False # Manual override
            elif ch in [10, 13]: # Enter
                cmd = command_input.strip().lower()
                parts = cmd.split()
                if parts:
                    try:
                        if parts[0] == "spin" and len(parts) == 2:
                            spin = max(0.0, min(1.0, float(parts[1])))
                            last_status = f"Spin set to {spin:.3f}"
                            auto_stabilize = False
                        elif parts[0] == "res" and len(parts) == 2:
                            resonance = max(0.0, min(1.0, float(parts[1])))
                            last_status = f"Resonance set to {resonance:.3f}"
                            auto_stabilize = False
                        elif parts[0] == "ent" and len(parts) == 2:
                            entanglement = max(0.0, min(1.0, float(parts[1])))
                            last_status = f"Entanglement set to {entanglement:.3f}"
                            auto_stabilize = False
                        elif parts[0] == "comet" and len(parts) == 2:
                            comet_coherence = max(0.0, min(1.0, float(parts[1])))
                            last_status = f"Comet set to {comet_coherence:.3f}"
                            auto_stabilize = False
                        elif parts[0] in ["reset", "r"]:
                            spin, resonance, entanglement, comet_coherence = 0.82, 0.68, 0.71, 0.33
                            skiss_noise = False
                            auto_stabilize = False
                            last_status = "Reset to baseline anchors"
                        elif parts[0] in ["noise", "n"]:
                            skiss_noise = not skiss_noise
                            last_status = f"Noise injection {'ON' if skiss_noise else 'OFF'}"
                        elif parts[0] in ["auto", "a"]:
                            auto_stabilize = not auto_stabilize
                            last_status = f"Auto-Stabilizer {'ON' if auto_stabilize else 'OFF'}"
                        elif parts[0] in ["quit", "exit", "q"]:
                            running = False
                        else:
                            last_status = f"Unknown command: {parts[0]}"
                    except ValueError:
                        last_status = "Error: Invalid value"
                command_input = ""
            elif ch in [8, 127, curses.KEY_BACKSPACE]:
                command_input = command_input[:-1]
            elif ch == ord('n') and not command_input:
                skiss_noise = not skiss_noise
                last_status = f"Noise injection {'ON' if skiss_noise else 'OFF'}"
            elif ch == ord('a') and not command_input:
                auto_stabilize = not auto_stabilize
                last_status = f"Auto-Stabilizer {'ON' if auto_stabilize else 'OFF'}"
            elif ch == ord('r') and not command_input:
                spin, resonance, entanglement, comet_coherence = 0.82, 0.68, 0.71, 0.33
                skiss_noise = False
                auto_stabilize = False
                last_status = "Reset to baseline anchors"
            elif ch == ord('q') and not command_input:
                running = False
            elif 32 <= ch <= 126:
                command_input += chr(ch)




if __name__ == "__main__":
    try:
        curses.wrapper(main_loop)
    except KeyboardInterrupt:
        pass
    print("\n\033[1;33mDashboard stopped. Horizon collapsed.\033[0m")
