import tkinter as tk
from tkinter import ttk
import numpy as np
import matplotlib
matplotlib.use("Agg")  # backend sigur pentru import
from matplotlib.figure import Figure

try:
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
except Exception as e:
    FigureCanvasTkAgg = None


class InducedCoherenceGUI:
    def __init__(self, master):
        self.master = master
        master.title("Induced Coherence Without Induced Emission - Quantum Interferometer Simulator")

        # Containere principale
        self.control_frame = ttk.Frame(master)
        self.control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)

        self.plot_frame = ttk.Frame(master)
        self.plot_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)

        # Parametri principali
        self.visibility = tk.DoubleVar(value=1.0)   # 0..1, coerență indusă (suprapunere idler)
        self.phase = tk.DoubleVar(value=0.0)        # 0..2π
        self.photons = tk.IntVar(value=2000)        # număr fotoni pe run
        self.blocker = tk.BooleanVar(value=False)   # blocaj pe Brațul 2?
        self.message_bits = tk.StringVar(value="10110")
        self.bit_threshold = tk.DoubleVar(value=0.4)  # prag pe vizibilitate pentru decodare

        # Construim panoul de control
        self._build_controls()

        # Construim zona de grafice
        self._build_plots()

        # Desen inițial
        self.update_plots()

    def _build_controls(self):
        # Titlu
        ttk.Label(self.control_frame, text="Control Panel", font=("Segoe UI", 12, "bold")).pack(pady=(0, 10))

        # Slider vizibilitate (coerență indusă)
        vis_frame = ttk.LabelFrame(self.control_frame, text="Induced Coherence (suprapunere Idler)")
        vis_frame.pack(fill=tk.X, pady=5)
        ttk.Scale(vis_frame, from_=0.0, to=1.0, variable=self.visibility,
                  command=lambda e: self.update_plots()).pack(fill=tk.X, padx=5, pady=5)
        ttk.Label(vis_frame, text="0 = deloc coerent, 1 = perfect coerent").pack(padx=5, pady=(0, 5))

        # Slider fază relativă
        phase_frame = ttk.LabelFrame(self.control_frame, text="Fază relativă între căi (φ)")
        phase_frame.pack(fill=tk.X, pady=5)
        ttk.Scale(phase_frame, from_=0.0, to=2*np.pi, variable=self.phase,
                  command=lambda e: self.update_plots()).pack(fill=tk.X, padx=5, pady=5)
        ttk.Label(phase_frame, text="0 … 2π").pack(padx=5, pady=(0, 5))

        # Slider număr de fotoni
        photon_frame = ttk.LabelFrame(self.control_frame, text="Număr fotoni simulați (Singles)")
        photon_frame.pack(fill=tk.X, pady=5)
        ttk.Scale(photon_frame, from_=100, to=10000, variable=self.photons,
                  command=lambda e: self.update_plots()).pack(fill=tk.X, padx=5, pady=5)
        ttk.Label(photon_frame, text="Afectează doar zgomotul statistic").pack(padx=5, pady=(0, 5))

        # Checkbutton blocaj Braț 2
        blocker_frame = ttk.Frame(self.control_frame)
        blocker_frame.pack(fill=tk.X, pady=5)
        ttk.Checkbutton(
            blocker_frame,
            text="Blocaj pe Brațul 2 (Idler)",
            variable=self.blocker,
            command=self.update_plots
        ).pack(anchor="w", padx=5)
        ttk.Label(
            blocker_frame,
            text="⟹ dacă e bifat: fotonii Martor devin distingibili, interferența dispare."
        ).pack(padx=5, pady=(0, 5))

        # Buton run simplu
        btn_frame = ttk.Frame(self.control_frame)
        btn_frame.pack(fill=tk.X, pady=10)
        ttk.Button(btn_frame, text="Simulează un run", command=self.update_plots).pack(fill=tk.X, padx=5)

        # Mod mesaje
        msg_frame = ttk.LabelFrame(self.control_frame, text="Mod mesaje (DOAR SIMULARE IDEALIZATĂ)")
        msg_frame.pack(fill=tk.X, pady=10)
        ttk.Label(msg_frame, text="Șir biți de trimis (0=blocaj, 1=coerență):").pack(anchor="w", padx=5, pady=(5, 0))
        ttk.Entry(msg_frame, textvariable=self.message_bits).pack(fill=tk.X, padx=5, pady=5)

        thresh_row = ttk.Frame(msg_frame)
        thresh_row.pack(fill=tk.X, pady=2)
        ttk.Label(thresh_row, text="Prag vizibilitate V pentru decodare:").pack(side=tk.LEFT, padx=5)
        ttk.Entry(thresh_row, textvariable=self.bit_threshold, width=5).pack(side=tk.LEFT, padx=5)

        ttk.Button(
            msg_frame,
            text="Rulează demo trimitere mesaje",
            command=self.run_message_demo
        ).pack(fill=tk.X, padx=5, pady=5)

        # Text pentru explicații și rezultate
        text_frame = ttk.LabelFrame(self.control_frame, text="Explicații & rezultate")
        text_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        self.text = tk.Text(text_frame, width=40, height=20, wrap="word")
        self.text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        self._write_intro_text()

    def _build_plots(self):
        if FigureCanvasTkAgg is None:
            ttk.Label(self.plot_frame, text="Matplotlib backend indisponibil.").pack()
            return

        self.fig = Figure(figsize=(6, 6), dpi=100)
        self.ax_intensity = self.fig.add_subplot(211)
        self.ax_hits = self.fig.add_subplot(212)

        self.fig.tight_layout(pad=3.0)

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.plot_frame)
        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

    def _write_intro_text(self):
        self.text.delete("1.0", tk.END)
        intro = (
            "Simulator: \"Coerență indusă fără emisie indusă\"\n\n"
            "Brațul 1: fotoni Semnal care ajung pe ecran și pot produce franje de interferență.\n"
            "Brațul 2: fotoni Martor (Idler) care, dacă sunt făcuți indistinguibili (suprapuși în cristal), "
            "fac ca fotonii de pe Brațul 1 să devină coerent superpuși.\n\n"
            "Sliderul de coerență modelează cât de bine se suprapun Martorii: 0 = deloc, 1 = perfect.\n"
            "Bifa „Blocaj pe Brațul 2” rupe suprapunerea și distruge interferența.\n\n"
            "IMPORTANT: Acesta este DOAR un model numeric, nu dovedește comunicare mai rapidă decât lumina. "
            "În fizica reală, un astfel de setup nu permite transmiterea de informație superluminică.\n"
        )
        self.text.insert(tk.END, intro)

    # ====== MODEL FIZIC SIMPLIFICAT ======

    def _compute_intensity_profile(self, vis, phase):
        """
        Model: I(x) ~ 1 + V cos(2x + φ),
        unde V este vizibilitatea (0..1), x poziția pe ecran.
        """
        x = np.linspace(-np.pi, np.pi, 500)
        I0 = 1.0
        I = I0 * (1.0 + vis * np.cos(2.0 * x + phase))
        I = np.clip(I, 0.0, None)  # fără intensitate negativă
        return x, I

    def _sample_photon_hits(self, x, I, n_photons):
        """Eșantionăm coordonate de „fotoni” proporțional cu intensitatea."""
        prob = I / np.sum(I)
        idx = np.random.choice(len(x), size=n_photons, p=prob)
        hits_x = x[idx]
        return hits_x

    def _estimate_visibility(self, I):
        """Estimăm vizibilitatea V_meas din profilul de intensitate."""
        I_max = float(np.max(I))
        I_min = float(np.min(I))
        if I_max + I_min == 0:
            return 0.0
        return (I_max - I_min) / (I_max + I_min)

    # ====== ACTUALIZARE GRAFICE ======

    def update_plots(self):
        if FigureCanvasTkAgg is None:
            return

        # Vizibilitate efectivă: dacă e blocat Brațul 2, nu mai e coerență
        base_vis = self.visibility.get()
        blocked = self.blocker.get()
        vis_eff = 0.0 if blocked else base_vis

        phase = self.phase.get()
        n_photons = max(50, int(self.photons.get()))

        x, I = self._compute_intensity_profile(vis_eff, phase)
        hits_x = self._sample_photon_hits(x, I, n_photons)

        V_meas = self._estimate_visibility(I)

        # Plot intensitate
        self.ax_intensity.clear()
        self.ax_intensity.plot(x, I, linewidth=1.5)
        self.ax_intensity.set_title("Brațul 1: Intensitatea pe ecran (Singles)")
        self.ax_intensity.set_xlabel("Poziție x (unități arbitrare)")
        self.ax_intensity.set_ylabel("Intensitate (număr mediu de fotoni)")

        subtitle = f"Vizibilitate teoretică V = {vis_eff:.2f}, vizibilitate estimată V_meas ≈ {V_meas:.2f}"
        if blocked:
            subtitle += "  (Blocaj pe Brațul 2 ⇒ franje distruse)"
        else:
            subtitle += "  (Brațul 2 coerent ⇒ franje vizibile)"
        self.ax_intensity.text(
            0.02, 0.95, subtitle,
            transform=self.ax_intensity.transAxes,
            fontsize=8, va="top"
        )

        # Plot histogramă de fotoni
        self.ax_hits.clear()
        self.ax_hits.hist(hits_x, bins=40, density=False, alpha=0.8)
        self.ax_hits.set_title(f"Brațul 1: evenimente detectate (N = {n_photons})")
        self.ax_hits.set_xlabel("Poziție x")
        self.ax_hits.set_ylabel("Număr de fotoni")

        self.fig.tight_layout(pad=3.0)
        self.canvas.draw_idle()

    # ====== MOD DEMO „MESAJ” ======

    def run_message_demo(self):
        if FigureCanvasTkAgg is None:
            return

        bits_str = self.message_bits.get().strip()
        bits = [b for b in bits_str if b in ("0", "1")]
        if not bits:
            self.text.insert(tk.END, "\nNu s-au găsit biți valizi (0/1) în șir.\n")
            return

        threshold = max(0.0, min(1.0, float(self.bit_threshold.get())))

        self.text.insert(tk.END, f"\n--- DEMO MESAJ (simulare idealizată) ---\n")
        self.text.insert(tk.END, f"Biți trimiși (Brațul 2): {''.join(bits)}\n")
        self.text.insert(tk.END, f"Prag pentru vizibilitate V: {threshold:.2f}\n")

        decoded_bits = []

        phase = self.phase.get()
        n_photons = max(200, int(self.photons.get()))

        for i, b in enumerate(bits, start=1):
            if b == "1":
                vis_eff = self.visibility.get()
                blocked = False
            else:
                vis_eff = 0.0
                blocked = True

            x, I = self._compute_intensity_profile(vis_eff, phase)
            hits_x = self._sample_photon_hits(x, I, n_photons)
            V_meas = self._estimate_visibility(I)

            # „Decodare”: dacă V_meas ≥ prag ⇒ 1, altfel 0
            decoded = "1" if V_meas >= threshold else "0"
            decoded_bits.append(decoded)

            self.text.insert(
                tk.END,
                f"Bit {i}: trimis {b}, blocaj={'DA' if blocked else 'NU'}, "
                f"V_meas ≈ {V_meas:.2f} ⇒ decodat {decoded}\n"
            )

        decoded_str = "".join(decoded_bits)
        self.text.insert(tk.END, f"Rezultat final decodare (din Brațul 1): {decoded_str}\n")

        errors = sum(1 for a, b in zip(bits, decoded_bits) if a != b)
        self.text.insert(tk.END, f"Erori de bit: {errors} din {len(bits)}\n")

        self.text.insert(
            tk.END,
            "\nATENȚIE: Acest demo arată DOAR cum ar arăta un protocol ipotetic "
            "într-un model simplificat. În mecanica cuantică reală,\n"
            "nu se poate transmite informație mai repede decât lumina prin astfel de trucuri cu coerența indusă.\n"
        )
        self.text.see(tk.END)

        # Titlu pentru ultima simulare
        self.fig.suptitle("Ultimul bit simulat în modul mesaj", fontsize=10)
        self.update_plots()


def main():
    root = tk.Tk()
    # Stil minim „futurist” (în limitele Tkinter)
    try:
        style = ttk.Style()
        if "clam" in style.theme_names():
            style.theme_use("clam")
    except Exception:
        pass

    app = InducedCoherenceGUI(root)
    root.mainloop()


if __name__ == "__main__":
    main()
