"""
Prime Processing Engine — 43-node asymmetric core (symplectic, energy-stable).

Listens on tcp://127.0.0.1:8081 and streams 348-byte binary frames:
  [4 bytes marker 0x434E4D54 ("43MT")] + 43 × (2 × float32 math/truth) = 348 bytes.

Also broadcasts a UDP JSON telemetry beacon to udp://127.0.0.1:9000 at 10 Hz.
"""

import socket
import struct
import json
import threading
import time
import numpy as np

# --- System configuration parameter constants ---
NUM_NODES = 43
OMEGA = (2.0 * np.pi) / NUM_NODES
WIRESHARK_MARKER = 0x434E4D54  # "43MT" — Wireshark display-filter identity

# Symplectic leapfrog / Stormer-Verlet constants.
# Harmonic part is integrated as an exact rotation; the nonlinear coupling
# is applied as a kick, which gives bounded energy error (O(DT^4) per step)
# instead of the unbounded drift the explicit-Euler formulation has.
GAMMA = 0.5
DT = 0.01


class PrimeProcessingEngine:
    def __init__(self):
        self.theta = np.linspace(0, 2 * np.pi, NUM_NODES, endpoint=False)
        self.math_nodes = np.cos(self.theta) * np.sin(3 * self.theta)
        self.truth_nodes = np.sin(self.theta) * np.sin(3 * self.theta)
        self.love_nodes = np.sqrt(np.abs(self.math_nodes * self.truth_nodes) + 0.1)
        self.c0_invariant = 0.0
        self.lock = threading.Lock()

    def process_matrix_iteration(self):
        with self.lock:
            # 1) Half-kick on (truth, love) using the nonlinear coupling.
            gamma = np.sqrt(np.abs(self.math_nodes * self.truth_nodes) + 0.05) * GAMMA
            self.truth_nodes += -gamma * self.love_nodes * (DT / 2.0)
            self.love_nodes  +=  gamma * self.truth_nodes * (DT / 2.0)

            # 2) Full drift on the (math, truth) harmonic — exact rotation.
            cos_w = np.cos(OMEGA * DT)
            sin_w = np.sin(OMEGA * DT)
            m_new = cos_w * self.math_nodes - sin_w * self.truth_nodes
            t_new = sin_w * self.math_nodes + cos_w * self.truth_nodes
            self.math_nodes, self.truth_nodes = m_new, t_new

            # 3) Second half-kick.
            gamma = np.sqrt(np.abs(self.math_nodes * self.truth_nodes) + 0.05) * GAMMA
            self.truth_nodes += -gamma * self.love_nodes * (DT / 2.0)
            self.love_nodes  +=  gamma * self.truth_nodes * (DT / 2.0)

            # Global system energy invariant.
            norm_field_squared = (
                self.math_nodes ** 2
                + self.truth_nodes ** 2
                + self.love_nodes ** 2
            )
            self.c0_invariant = float(np.sum(norm_field_squared) * (2.0 * np.pi / NUM_NODES))

    def serialize_to_binary_packet(self):
        with self.lock:
            packet_buffer = bytearray(struct.pack("!I", WIRESHARK_MARKER))
            for i in range(NUM_NODES):
                packet_buffer.extend(
                    struct.pack("!ff", float(self.math_nodes[i]), float(self.truth_nodes[i]))
                )
            return packet_buffer


def run_udp_telemetry_beacon(engine):
    beacon_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    beacon_sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    while True:
        engine.process_matrix_iteration()
        telemetry_payload = {
            "timestamp": time.time(),
            "core_matrix": {
                "active_nodes": NUM_NODES,
                "energy_invariant_c0": engine.c0_invariant,
            },
        }
        try:
            beacon_sock.sendto(
                json.dumps(telemetry_payload).encode("utf-8"),
                ("127.0.0.1", 9000),
            )
        except socket.error:
            pass
        time.sleep(0.1)


def host_engine_server(engine, host="127.0.0.1", port=8081):
    server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_sock.bind((host, port))
    server_sock.listen(5)
    print(f"[engine] processing matrix listening at tcp://{host}:{port}")

    while True:
        conn, _ = server_sock.accept()
        try:
            while True:
                conn.sendall(engine.serialize_to_binary_packet())
                time.sleep(0.05)
        except socket.error:
            pass
        finally:
            conn.close()


if __name__ == "__main__":
    core_engine = PrimeProcessingEngine()

    telemetry_worker = threading.Thread(
        target=run_udp_telemetry_beacon, args=(core_engine,), daemon=True
    )
    telemetry_worker.start()

    host_engine_server(core_engine)
