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 API KEY
# ==========================================
def obtine_api_key():
    api_key = ""
    
    def on_submit():
        nonlocal api_key
        api_key = entry.get().strip()
        if not api_key:
            messagebox.showwarning("Atenție", "Te rog să introduci o cheie API validă!")
            return
        root.destroy()
        
    def on_closing():
        root.destroy()
        exit()

    root = tk.Tk()
    root.title("Autentificare IBM Quantum")
    root.geometry("450x150")
    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)).pack(pady=15)
    entry = tk.Entry(root, width=50, show="*", font=("Arial", 10))
    entry.pack(pady=5)
    btn = tk.Button(root, text="Start Experiment", command=on_submit, bg="#0f62fe", fg="white", font=("Arial", 10, "bold"))
    btn.pack(pady=10)
    root.bind('<Return>', lambda event: on_submit())
    root.mainloop()
    return api_key

API_KEY = obtine_api_key()

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}")

delay_time_us = 100 

# ==========================================
# 2. CONSTRUIREA CIRCUITELOR LOGICE
# ==========================================
print("Construim circuitele cuantice...")

# CAZUL 0
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)

# CAZUL 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("\nTrimitem Cazul 0 in coada de asteptare...")
job_0 = sampler.run([isa_qc_0], shots=2048)

print("Trimitem Cazul 1 in coada de asteptare...")
job_1 = sampler.run([isa_qc_1], shots=2048)

print("\nAsteptam finalizarea executiei (te rog sa lasi fereastra deschisa)...")
print("Acest proces poate dura de la cateva minute la cateva ore in functie de coada de la IBM.")

# Extragem rezultatele folosind circuitele transpilate
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)

# ==========================================
# 6. GENERAREA GRAFICULUI
# ==========================================
print("Generam graficul...")
fig, ax = plt.subplots(figsize=(10, 6))
plot_histogram(
    [counts_0, counts_1], 
    legend=['Cazul 0 (Pastrare)', 'Cazul 1 (Stergere)'],
    title="Distributia starilor cuantice: Cazul 0 vs Cazul 1",
    ax=ax
)
plt.savefig('grafic_rezultate.png')
print("Graficul a fost salvat ca 'grafic_rezultate.png'")

# ==========================================
# 7. GENERAREA FISIERULUI TEXT
# ==========================================
print("Generam raportul text...")
raport = f"""=======================================================
RAPORT EXPERIMENT: COMUNICARE CUANTICA SI SUPERLUMINALITATE
Procesor utilizat: {backend.name}
Numar de masuratori (shots): 2048
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 ({(bob_0_caz0/2048)*100:.2f}%)
- Bob a masurat '1' de {bob_1_caz0} ori ({(bob_1_caz0/2048)*100:.2f}%)

In CAZUL 1:
- Bob a masurat '0' de {bob_0_caz1} ori ({(bob_0_caz1/2048)*100:.2f}%)
- Bob a masurat '1' de {bob_1_caz1} ori ({(bob_1_caz1/2048)*100:.2f}%)

3. CONCLUZIE EXPERIMENTALA
-------------------------------------------------------
Indiferent ce a ales Alice sa faca, distributia starii lui Bob 
este de aproximativ 50% pentru '0' si 50% pentru '1'.
Acest lucru demonstreaza practic "Teorema fara semnalizare" 
(No-Signaling Theorem) in limitele fizicii cuantice actuale.
"""

with open('raport_experiment.txt', 'w') as f:
    f.write(raport)

print("Raportul a fost salvat ca 'raport_experiment.txt'")
print("Proces incheiat cu succes! Poti gasi fisierele in acelasi folder cu programul.")
