import numpy as np
from scipy.constants import c, h, hbar
from typing import Tuple, List
import matplotlib.pyplot as plt

def ascii_to_binary(text: str) -> str:
    """Convertește text ASCII în secvență binară"""
    return ''.join(format(ord(char), '08b') for char in text)

def binary_to_ascii(binary: str) -> str:
    """Convertește secvență binară în text ASCII"""
    # Verificăm dacă lungimea șirului binar este multiplu de 8
    if len(binary) % 8 != 0:
        binary = binary.zfill(((len(binary) // 8) + 1) * 8)
    
    # Convertim fiecare grup de 8 biți în caracter ASCII
    return ''.join(chr(int(binary[i:i+8], 2)) for i in range(0, len(binary), 8))

class RetrocausalQuantumChannel:
    def __init__(self, fiber_length: float = 10.0):
        self.FIBER_LENGTH = fiber_length * 1000
        self.REFRACTIVE_INDEX = 1.5
        self.WAVELENGTH = 702e-9
        self.BBO_EFFICIENCY = 2.73e5
        self.PUMP_POWER = 1e-3
        
    def calculate_propagation_time(self) -> float:
        return self.FIBER_LENGTH * self.REFRACTIVE_INDEX / c
    
    def wavefunction_bbo(self, t: float) -> np.ndarray:
        E_photon = h * c / self.WAVELENGTH
        phase = E_photon * t / hbar
        
        return np.array([
            [0],
            [1/np.sqrt(2)],
            [-1/np.sqrt(2)],
            [0]
        ]) * np.exp(1j * phase)
    
    def retrocausal_propagator(self, t: float) -> np.ndarray:
        t_fiber = self.calculate_propagation_time()
        
        U_retro = np.array([
            [np.exp(-1j * t/t_fiber), 0, 0, 0],
            [0, np.exp(1j * t/t_fiber), 0, 0],
            [0, 0, np.exp(1j * t/t_fiber), 0],
            [0, 0, 0, np.exp(-1j * t/t_fiber)]
        ])
        
        return U_retro
    
    def simulate_transmission(self, message: str, detection_window: float = 50e-6) -> Tuple[str, List[float]]:
        received_bits = []
        detection_probabilities = []
        
        t_fiber = self.calculate_propagation_time()
        print(f"\nTimp propagare prin fibră: {t_fiber*1e6:.2f} μs")
        
        for i, bit in enumerate(message):
            t_detection = -detection_window
            
            psi_0 = self.wavefunction_bbo(t_detection)
            U = self.retrocausal_propagator(t_detection)
            psi_final = U @ psi_0
            
            if bit == '1':
                prob = float(np.abs(psi_final[1][0])**2)
            else:
                prob = float(np.abs(psi_final[2][0])**2)
                
            quantum_noise = float(np.random.normal(0, 0.1))
            detection_prob = min(1.0, max(0.0, prob + quantum_noise))
            
            received_bit = '1' if detection_prob > 0.5 else '0'
            
            print(f"\nBit {i+1} din {len(message)}:")
            print(f"t = {t_detection*1e6:.1f}μs: Detecție retrocauzală")
            print(f"t = 0μs: Transmisie")
            print(f"Probabilitate detecție: {detection_prob:.3f}")
            
            received_bits.append(received_bit)
            detection_probabilities.append(detection_prob)
            
        return ''.join(received_bits), detection_probabilities
    
    def plot_results(self, message: str, probabilities: List[float]):
        fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
        
        times = np.linspace(-50, 0, len(message))
        ax1.plot(times, probabilities, 'b.-', label='Probabilitate detecție')
        ax1.axvline(x=-50, color='r', linestyle='--', label='Moment detecție')
        ax1.axvline(x=0, color='g', linestyle='--', label='Moment transmisie')
        ax1.set_xlabel('Timp (μs)')
        ax1.set_ylabel('Probabilitate')
        ax1.set_title('Probabilități Detecție Retrocauzală')
        ax1.grid(True)
        ax1.legend()
        
        x = np.arange(len(message))
        width = 0.35
        ax2.bar(x - width/2, [int(b) for b in message], width, 
               label='Biți transmiși', color='blue', alpha=0.5)
        ax2.bar(x + width/2, probabilities, width,
               label='Prob. detecție', color='red', alpha=0.5)
        ax2.set_xlabel('Poziție bit')
        ax2.set_ylabel('Valoare/Probabilitate')
        ax2.set_title('Comparație Biți vs. Probabilități')
        ax2.legend()
        
        plt.tight_layout()
        plt.show()

def main():
    print("Experiment de Comunicare Cuantică Retrocauzală")
    print("---------------------------------------------")
    
    channel = RetrocausalQuantumChannel()
    
    # Solicitare mesaj ASCII
    ascii_message = input("\nIntroduceți mesajul ASCII: ")
    binary_message = ascii_to_binary(ascii_message)
    
    print(f"\nMesaj ASCII: {ascii_message}")
    print(f"Mesaj binar: {binary_message}")
    
    print("\nÎncepere simulare transmisie retrocauzală...")
    received_binary, probabilities = channel.simulate_transmission(binary_message)
    received_ascii = binary_to_ascii(received_binary)
    
    print("\nRezultate finale:")
    print(f"Mesaj ASCII transmis:    {ascii_message}")
    print(f"Mesaj ASCII primit:      {received_ascii}")
    print(f"Mesaj binar transmis:    {binary_message}")
    print(f"Mesaj binar primit:      {received_binary}")
    print(f"Număr total biți:        {len(binary_message)}")
    print(f"Biți transmiși corect:   {sum(1 for a, b in zip(binary_message, received_binary) if a == b)}")
    print(f"Acuratețe medie:         {np.mean(probabilities):.2f}%")
    
    channel.plot_results(binary_message, probabilities)

if __name__ == "__main__":
    main()
