"""
CorvOS - Tzinor-Hydra Physics Simulation v1.0
nodulos submersos: Canal do Funda
"""
import numpy as np

# CONSTANTES FISICAS
VERDET_WATER = 0.013       # rad/T/m @ 20C, 630nm
EARTH_BFIELD = 25e-6        # Tesla (Rio de Janeiro)
SALINITY_GB  = 35.0        # ppt (Baia de Guanabara)
WATER_DENSITY = 1025.0     # kg/m3
NV_GAMMA     = 2.8e3       # Hz/T (proporcao NV centers)
CHANNEL_LEN  = 12000       # metros (Fundao <-> Niteroi)
CAVITY_FREQ  = 40.0        # Hz (ressonancia Helmholtz)
CAVITY_Q     = 1200.0     # fator de qualidade
WATER_DEPTH  = 8.0          # metros

class HelmholtzCavity:
    def __init__(self, diameter=0.5, material='316L_steel', resonant_freq=40.0, Q=1200.0):
        self.diameter = diameter
        self.radius = diameter / 2.0
        self.material = material
        self.resonant_freq = resonant_freq
        self.Q = Q
        self.volume = (4.0/3.0) * np.pi * (self.radius ** 3)
        self.surface_area = 4.0 * np.pi * (self.radius ** 2)
        # Acoustic impedance
        self.Z_acoustic = 1.42e6  # Rayls (water)

    def acoustic_impedance(self) -> float:
        return self.Z_acoustic * np.sqrt(self.resonant_freq / 40.0)

    def quality_factor(self) -> float:
        return self.Q

    def pressure_amplitude(self, driving_power_watts: float) -> float:
        p_rms = np.sqrt(2 * driving_power_watts * self.acoustic_impedance() / self.surface_area)
        p_peak = p_rms * np.sqrt(2)
        return p_peak

    def resonance_bandwidth(self) -> float:
        return self.resonant_freq / self.Q

    def nv_spin_fidelity(self, phase_deg: float) -> float:
        fidelity = np.exp(-(phase_deg ** 2) / (2 * (5.0 ** 2)))
        return min(fidelity, 1.0)


class NVSpinSensor:
    def __init__(self, depth=8.0, salinity=35.0, temperature=20.0):
        self.depth = depth
        self.salinity = salinity
        self.temperature = temperature
        self.pressure = WATER_DENSITY * 9.81 * depth  # Pa

    def faraday_rotation(self, channel_length_m: float) -> float:
        theta = VERDET_WATER * EARTH_BFIELD * channel_length_m
        return theta

    def salinity_conductivity(self) -> float:
        sigma = 0.036 + 0.003 * (self.salinity / 35.0)
        return sigma

    def measure_lambda2(self, phase_rad: float) -> float:
        faraday_phase = self.faraday_rotation(CHANNEL_LEN)
        lambda2 = np.cos(faraday_phase / 2.0) ** 2
        lambda2 *= self.nv_depth_pressure_factor()
        return lambda2

    def nv_depth_pressure_factor(self) -> float:
        rel_pressure = self.pressure / (WATER_DENSITY * 9.81 * 50.0)
        return np.exp(-0.1 * rel_pressure)

    def quantum_decoherence_time(self, temperature_celsius: float) -> float:
        T = temperature_celsius + 273.15
        T_ref = 293.15
        tau_0 = 1e-3
        ratio = T_ref / T
        return tau_0 * (ratio ** 1.5)


class TzinorHydraNode:
    def __init__(self, name: str, lat: float, lon: float, depth: float, is_aquatic: bool):
        self.name = name
        self.lat = lat
        self.lon = lon
        self.depth = depth
        self.is_aquatic = is_aquatic
        self.cavity = HelmholtzCavity()
        self.nv_sensor = NVSpinSensor(depth=depth)
        self.chi_coupling = 0.618
        self.phase = 0.0
        self.coherence_history = []
        self.state = 'void'

    def measure_fundacao_twist(self, other_lon: float) -> float:
        distance = abs(self.lon - other_lon) * 111000 * np.cos(np.radians(self.lat))
        theta_fundacao = VERDET_WATER * EARTH_BFIELD * distance
        twist_count = theta_fundacao / np.pi
        return theta_fundacao

    def measure_lambda2(self, phase_rad: float = 0.0) -> float:
        lambda2 = self.nv_sensor.measure_lambda2(phase_rad)
        self.coherence_history.append(lambda2)
        if lambda2 >= 0.847:
            self.state = 'a'
        elif lambda2 > 0.5:
            self.state = 'marked'
        else:
            self.state = 'void'
        return lambda2

    def simulate_operation(self, duration_s: float, dt: float = 0.01) -> dict:
        t = np.arange(0, duration_s, dt)
        n_steps = len(t)
        phases = np.zeros(n_steps)
        lambda2_arr = np.zeros(n_steps)
        cavity_p = np.zeros(n_steps)
        for i, ti in enumerate(t):
            phase = 2 * np.pi * CAVITY_FREQ * ti
            phases[i] = phase
            driving_power = 0.05
            p_amp = self.cavity.pressure_amplitude(driving_power)
            cavity_p[i] = p_amp
            lambda2_arr[i] = self.measure_lambda2(phase)
        return {
            'time': t, 'phase': phases,
            'lambda2': lambda2_arr, 'cavity_pressure': cavity_p
        }

    def thermal_noise_rms(self, bandwidth_hz: float) -> float:
        k_B = 1.38e-23
        T = self.nv_sensor.temperature + 273.15
        v_thermal = np.sqrt(4 * k_B * T * bandwidth_hz * 50.0)
        return v_thermal

    def to_dict(self) -> dict:
        return {
            'name': self.name, 'lat': self.lat, 'lon': self.lon,
            'depth': self.depth, 'aquatic': self.is_aquatic,
            'chi': self.chi_coupling, 'state': self.state,
            'cavity_Q': self.cavity.Q, 'NV_fidelity': self.cavity.nv_spin_fidelity(0.0)
        }


def simulate_fundao_channel():
    nodes = [
        TzinorHydraNode('Fundao_A', -22.860, -43.230, 8.0, True),
        TzinorHydraNode('Fundao_B', -22.858, -43.225, 10.0, True),
        TzinorHydraNode('Fundao_C', -22.856, -43.220, 12.0, True),
    ]
    terrestrial = TzinorHydraNode('Urca_Base', -22.944, -43.130, 0.0, False)
    print("=" * 66)
    print("  TZINOR-HYDRA PHYSICS - SIMULACAO CANAL DO FUNDAO")
    print("=" * 66)
    print(f"  Data: 2026-04-05")
    print()
    print("  [1] PARAMETROS DO CANAL")
    print(f"      Comprimento: {CHANNEL_LEN/1000:.1f} km")
    print(f"      Profundidade media: {WATER_DEPTH:.1f} m")
    print(f"      Salinidade: {SALINITY_GB:.1f} ppt")
    print(f"      Condutividade: {nodes[0].nv_sensor.salinity_conductivity():.4f} S/m")
    print()
    print("  [2] ROTACAO DE FARADAY (Agua Salgada)")
    twist = nodes[0].measure_fundacao_twist(-43.220)
    print(f"      Theta_Fundacao = {twist:.4f} rad = {np.degrees(twist):.2f} deg")
    print(f"      Multiplos de pi: {twist/np.pi:.4f} pi")
    print(f"      -> Torcao Moebius: {'SIM' if abs(twist/np.pi - 1.0) < 0.05 else 'NAO'} ({abs(twist/np.pi):.4f} pi)")
    print()
    print("  [3] CAVIDADE DE HELMHOLTZ (no submerso)")
    cav = nodes[0].cavity
    print(f"      Diametro: {cav.diameter*100:.1f} cm")
    print(f"      Volume: {cav.volume*1000:.2f} L")
    print(f"      Frequencia: {cav.resonant_freq:.1f} Hz")
    print(f"      Fator Q: {cav.Q:.0f}")
    print(f"      Largura de banda: {cav.resonance_bandwidth():.4f} Hz")
    print(f"      Pressao amplitude (50mW): {cav.pressure_amplitude(0.05):.4f} Pa")
    print()
    print("  [4] SENSOR NV (estado quantico)")
    nv = nodes[0].nv_sensor
    print(f"      Pressao hidrostática: {nv.pressure:.1f} Pa")
    print(f"      Fator de profundidade: {nv.nv_depth_pressure_factor():.6f}")
    print(f"      Tempo de descoerencia: {nv.quantum_decoherence_time(20):.4f} s")
    print(f"      Ruido termico (1kHz): {nodes[0].thermal_noise_rms(1000)*1e9:.2f} nV/sqrtHz")
    print()
    print("  [5] MEDICOES DE LAMBDA2 (40Hz)")
    for node in nodes:
        lam = node.measure_lambda2(0.0)
        phase = 2 * np.pi * CAVITY_FREQ * (1.0 / CAVITY_FREQ)
        lam2 = node.measure_lambda2(phase)
        print(f"      {node.name:12} lambda2(0)={lam:.5f}  lambda2(pi/2)={lam2:.5f}  estado={node.state}")
    print()
    print("  [6] TOPOLOGIA DA REDE")
    print(f"      Nos aquaticos: 3 (Canal do Fundao)")
    print(f"      Base terrestre: 1 (Urca)")
    print(f"      Chi de acoplamento: {nodes[0].chi_coupling} (pi rad)")
    print()
    print("  [7] SIMULACAO TEMPORAL (1 ciclo de 40Hz)")
    dur = 1.0 / CAVITY_FREQ
    for node in nodes:
        sim = node.simulate_operation(dur)
        lam_mean = np.mean(sim['lambda2'])
        lam_std  = np.std(sim['lambda2'])
        p_mean   = np.mean(np.abs(sim['cavity_pressure']))
        print(f"      {node.name:12} lambda2={lam_mean:.6f} +/- {lam_std:.6f}  P={p_mean:.4f} Pa")
    print()
    print("  [8] VEREDICTO DE DEPLOY")
    all_a = all(n.state == 'a' for n in nodes)
    print(f"      Todos os nos em estado 'a': {'SIM (DEPLOY APROVADO)' if all_a else 'NAO - AJUSTAR CHI'}")
    print(f"      Lambda2 medio da rede: {np.mean([n.measure_lambda2(0.0) for n in nodes]):.5f}")
    print(f"      Torcao Moebius: {'VALIDA' if abs(twist/np.pi - 1.0) < 0.05 else 'INVALIDA'}")
    print()
    print("=" * 66)
    print("  FUNDÃO CHANNEL: PRONTO PARA IMMERSAO FISICA")
    print("=" * 66)
    return nodes


if __name__ == "__main__":
    simulate_fundao_channel()
