import os
import tkinter as tk
from tkinter import messagebox
import matplotlib.pyplot as plt
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.visualization import plot_histogram

# ==========================================
# 0. INTERFAȚA GRAFICĂ PENTRU SETĂRI
# ==========================================
def obtine_date_interfata():
    date_returnate = {"api_key": "", "delay": 2, "shots": 2048}
    
    def on_submit():
        api_key_input = entry_api.get().strip()
        if not api_key_input:
            messagebox.showwarning("Atenție", "Te rog să introduci o cheie API validă!")
            return
            
        try:
            delay_input = int(entry_delay.get().strip())
            shots_input = int(entry_shots.get().strip())
            
            if shots_input < 1 or delay_input < 0:
                raise ValueError
                
        except ValueError:
            messagebox.showwarning("Eroare", "Delay-ul și numărul de încercări trebuie să fie numere întregi pozitive!")
            return
            
        date_returnate["api_key"] = api_key_input
        date_returnate["delay"] = delay_input
        date_returnate["shots"] = shots_input
        root.destroy()
        
    def on_closing():
        root.destroy()
        exit()

    root = tk.Tk()
    root.title("Setări Experiment IBM Quantum")
    root.geometry("450x320")
    root.eval('tk::PlaceWindow . center')
    root.protocol("WM_DELETE_WINDOW", on_closing)

    tk.Label(root, text="Introdu cheia ta API de la IBM Quantum:", font=("Arial", 10, "bold")).pack(pady=(15, 2))
    entry_api = tk.Entry(root, width=50, show="*", font=("Arial", 10))
    entry_api.pack(pady=5)
    
    tk.Label(root, text="Timp de întârziere pentru Bob în microsecunde\n(Default: 2 µs):", font=("Arial", 10)).pack(pady=(10, 2))
    entry_delay = tk.Entry(root, width=20, font=("Arial", 10), justify="center")
    entry_delay.insert(0, "2")
    entry_delay.pack(pady=5)
    
    tk.Label(root, text="Număr de încercări / Shots\n(Default: 2048):", font=("Arial", 10)).pack(pady=(10, 2))
    entry_shots = tk.Entry(root, width=20, font=("Arial", 10), justify="center")
    entry_shots.insert(0, "2048")
    entry_shots.pack(pady=5)

    btn = tk.Button(root, text="Start Experiment", command=on_submit, bg="#0f62fe", fg="white", font=("Arial", 10, "bold"))
    btn.pack(pady=15)
    
    root.bind('<Return>', lambda event: on_submit())
    root.mainloop()
    
    return date_returnate

setari = obtine_date_interfata()
API_KEY = setari["api_key"]
delay_time_us = setari["delay"]
shots_count = setari["shots"]

if not API_KEY:
    print("Nu a fost introdusă nicio cheie API. Se oprește execuția.")
    exit()

# ==========================================
# 1. CONECTAREA LA IBM QUANTUM
# ==========================================
print("\nNe conectam la IBM Quantum...")
try:
    service = QiskitRuntimeService(channel="ibm_quantum_platform", token=API_KEY)
except Exception as e:
    print(f"Eroare la autentificare! Verifica daca cheia API este corecta. Detalii eroare: {e}")
    exit()

backend = service.least_busy(operational=True, simulator=False)
print(f"Autentificare reusita! Am selectat procesorul cuantic: {backend.name}")

# ==========================================
# 2. CONSTRUIREA CIRCUITELOR LOGICE
# ==========================================
print(f"Construim circuitele cu un delay de {delay_time_us} microsecunde...")

qc_0 = QuantumCircuit(2, 2)
qc_0.h(0)
qc_0.cx(0, 1)
qc_0.measure(0, 0)
qc_0.delay(delay_time_us, 1, unit='us')
qc_0.measure(1, 1)

qc_1 = QuantumCircuit(2, 2)
qc_1.h(0)
qc_1.cx(0, 1)
qc_1.h(0)
qc_1.measure(0, 0)
qc_1.delay(delay_time_us, 1, unit='us')
qc_1.h(1)
qc_1.measure(1, 1)

# ==========================================
# 3. TRANSPILAREA CIRCUITELOR PENTRU HARDWARE
# ==========================================
print(f"Traducem (transpilam) circuitele pentru arhitectura {backend.name}...")
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc_0 = pm.run(qc_0)
isa_qc_1 = pm.run(qc_1)

# ==========================================
# 4. EXECUTAREA PE PROCESORUL CUANTIC
# ==========================================
sampler = Sampler(backend)

print(f"\nTrimitem Cazul 0 in coada de asteptare ({shots_count} shots)...")
job_0 = sampler.run([isa_qc_0], shots=shots_count)

print(f"Trimitem Cazul 1 in coada de asteptare ({shots_count} shots)...")
job_1 = sampler.run([isa_qc_1], shots=shots_count)

print("\nAsteptam finalizarea executiei (te rog sa lasi fereastra deschisa)...")
counts_0 = job_0.result()[0].data.c.get_counts()
counts_1 = job_1.result()[0].data.c.get_counts()
print("\nExecutie finalizata cu succes!")

# ==========================================
# 5. PROCESAREA REZULTATELOR PENTRU BOB
# ==========================================
def obtine_statistici_bob(counts):
    bob_0 = 0
    bob_1 = 0
    for state, count in counts.items():
        if state[0] == '0': 
            bob_0 += count
        elif state[0] == '1': 
            bob_1 += count
    return bob_0, bob_1

bob_0_caz0, bob_1_caz0 = obtine_statistici_bob(counts_0)
bob_0_caz1, bob_1_caz1 = obtine_statistici_bob(counts_1)

# Calculăm deviația procentuală a lui Bob de la 50%
proc_0_caz0 = bob_0_caz0 / shots_count
proc_0_caz1 = bob_0_caz1 / shots_count

# Dacă oricare deviază cu mai mult de 8% de la 50/50, considerăm că a intervenit zgomotul termic
if abs(proc_0_caz0 - 0.5) > 0.08 or abs(proc_0_caz1 - 0.5) > 0.08:
    status_text = f"De cercetat ce se intampla  !"
    box_color = "lightcoral"
else:
    status_text = f"Experiment reușit! Distribuția de aprox. 50/50 confirmă Teorema Fără Semnalizare.\nBob nu primește nicio informație (FTL) doar privind propriul detector."
    box_color = "lightgreen"

# ==========================================
# 6. GENERAREA GRAFICULUI
# ==========================================
print("Generam graficul...")
fig, ax = plt.subplots(figsize=(10, 7)) # Am marit putin inaltimea pentru a incapea textul

plot_histogram(
    [counts_0, counts_1], 
    legend=['Cazul 0 (Pastrare)', 'Cazul 1 (Stergere)'],
    title=f"Distributia starilor: Cazul 0 vs Cazul 1 (Delay: {delay_time_us}µs, Shots: {shots_count})",
    ax=ax
)

# Adăugăm caseta de text inteligentă în partea de jos a graficului
plt.figtext(0.5, 0.02, status_text, ha="center", fontsize=11, fontweight="bold",
            bbox={"facecolor": box_color, "alpha": 0.6, "pad": 8, "boxstyle": "round,pad=0.5"})
plt.subplots_adjust(bottom=0.20) # Facem loc pentru caseta de text jos

plt.savefig('grafic_rezultate_custom.png')
print("Graficul a fost salvat ca 'grafic_rezultate_custom.png'")

# ==========================================
# 7. GENERAREA FISIERULUI TEXT
# ==========================================
print("Generam raportul text...")
raport = f"""=======================================================
RAPORT EXPERIMENT: COMUNICARE CUANTICA
Procesor utilizat: {backend.name}
Numar de masuratori (shots): {shots_count}
Intarziere aplicata pentru Bob: {delay_time_us} microsecunde
=======================================================

1. DATE BRUTE (Format: 'Qubit_Bob Qubit_Alice' : Numar_Aparitii)
-------------------------------------------------------
Cazul 0 (Alice a masurat calea): {counts_0}
Cazul 1 (Alice a sters calea): {counts_1}

2. ANALIZA STATISTICA A LUI BOB
-------------------------------------------------------
In CAZUL 0:
- Bob a masurat '0' de {bob_0_caz0} ori ({proc_0_caz0*100:.2f}%)
- Bob a masurat '1' de {bob_1_caz0} ori ({(bob_1_caz0/shots_count)*100:.2f}%)

In CAZUL 1:
- Bob a masurat '0' de {bob_0_caz1} ori ({proc_0_caz1*100:.2f}%)
- Bob a masurat '1' de {bob_1_caz1} ori ({(bob_1_caz1/shots_count)*100:.2f}%)

3. CONCLUZIE EXPERIMENTALA AUTOMATA
-------------------------------------------------------
Mesaj generat: 
{status_text}
"""

with open('raport_experiment_custom.txt', 'w', encoding='utf-8') as f:
    f.write(raport)

print("Raportul a fost salvat ca 'raport_experiment_custom.txt'")
print("Proces incheiat cu succes!")
