import math
from qiskit import QuantumCircuit
from qiskit.circuit.library import QFT

import quantum_utils_v1 as q

# ============================================================================
# PARAMETRI — LAKO PODESIVO
# ============================================================================
n_count = 3   # broj mernih kubita (možeš menjati)
phi = 1 / 8   # faza koju procenjujemo (φ)

# ============================================================================
# OPIS OPERATORA
# ============================================================================
# Operator U je definisan kao:
#     U|1⟩ = e^{2πi * φ}|1⟩
# pa je osnovni fazni ugao:
angle = 2 * math.pi * phi

# ============================================================================
# INICIJALIZACIJA KVANTNOG KOLA
# ============================================================================
# Imamo:
# - n_count kubita za merni registar,
# - 1 kubit za sistem (eigenstanje).
qc = QuantumCircuit(n_count + 1, n_count)
qc.barrier()
q.show_bloch_sphere(qc)

# ============================================================================
# KORAK 1: Priprema ciljnog kubita u eigenstanje |1⟩
# ============================================================================
target = n_count  # indeks ciljnog kubita
qc.x(target)
qc.barrier()
q.show_bloch_sphere(qc)

# ============================================================================
# KORAK 2: H-gejt na mernim kubitima
# ============================================================================
for qubit in range(n_count):
    qc.h(qubit)
qc.barrier()
q.show_bloch_sphere(qc)

# ============================================================================
# KORAK 3: Primena kontrolisanih U^(2^k) operacija
# ============================================================================
# Svaki merni kubit kontroliše eksponencijalnu primenu operatora U
for k in range(n_count):
    repetitions = 2 ** k
    for _ in range(repetitions):
        qc.cp(angle, k, target)
qc.barrier()
q.show_bloch_sphere(qc)

# ============================================================================
# KORAK 4: Inverzna Kvantna Furijeova Transformacija (iQFT)
# ============================================================================
# Automatski koristi QFT nad mernim kubitima
qc = qc.compose(QFT(num_qubits=n_count, inverse=True), list(range(n_count)))
qc.barrier()
q.show_bloch_sphere(qc)

# ============================================================================
# KORAK 5: Merenje
# ============================================================================
for n in range(n_count):
    qc.measure(n, n)

# ============================================================================
# PRIKAZI I ANALIZA
# ============================================================================
q.print_state(qc, "Konačno kvantno stanje:", True)
q.print_probabilities(qc, "Verovatnoće baznih stanja:")
q.show_qc(qc)
q.show_measurement(qc)

# ============================================================================
# OČEKIVANI ISHOD
# ============================================================================
# φ = 1/8 = 0.001₂
# Ako koristiš više mernih kubita, preciznost binarnog zapisa raste.
# Na primer:
#   n_count = 3 → |001⟩
#   n_count = 4 → |0010⟩
#   n_count = 5 → |00100⟩
# itd.
# ============================================================================
