from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
from utils import entangle, simulate, visualize

def vis_entanglement():
    qc = QuantumCircuit(2)
    qr = QuantumRegister(2)

    entangled_pair_circuit: QuantumCircuit  = entangle(qr, qc)
    result = simulate(entangled_pair_circuit, 1000)
    visualize(result)

print(vis_entanglement())




# Performs a quantum coin flip.
def quoin_flip():
    qc = QuantumCircuit(1, 1)
    qc.h(0)
    qc.measure(0, 0)

    counts = list(simulate(qc))

    if len(counts) == 1:
        if counts[0] == "1":
            print("Tails")
        else:
            print("Heads")
    else:
        print("Could not determine heads nor tails.")


def quantum_teleport():
    qr = QuantumRegister(3)
    qc = QuantumCircuit(qr)

    qc = entangle(qr[1], qr[2], qc)
    qc.cx(qr[0], qr[1])
    qc.h(qr[0])

    cr = ClassicalRegister(3)
    qc.measure(qr[0], cr[0])
    qc.mearsure(qr[1], cr[1])

    qc.x(qr[2]).c_if(cr[1], 1)  # Apply an X gate to q2 if cr1 is equal to 1
    qc.z(qr[2]).c_if(cr[0], 1)  # Apply a Z gate to q2 if cr0 is equal to 1

    return simulate(qc)


def four_qbit_bell_state():
    qr = QuantumRegister(4)
    qc = QuantumCircuit(qr)

    # First entangled pair
    q0 = qr[0]
    q1 = qr[1]
    qc.h(q0)
    qc.cx(q0, q1)

    # Second entangled pair
    q2 = qr[2]
    q3 = qr[3]
    qc.x(q2)
    qc.x(q3)
    qc.h(q2)
    qc.cx(q2, q3)

    cr = ClassicalRegister(4)
    qc.add_register(cr)
    qc.measure(q0, cr[0])
    qc.measure(q1, cr[1])
    qc.measure(q2, cr[2])
    qc.measure(q3, cr[3])
    return qc


def four_qubit_circuit():
    # Setup circuit
    qr = QuantumRegister(4)
    cr = ClassicalRegister(4)
    qc = QuantumCircuit()
    qc.add_register(qr)
    qc.add_register(cr)

    qc.h(qr[0])
    qc.cnot(qr[1], qr[0])
    qc.cnot(qr[2], qr[1])
    qc.cnot(qr[3], qr[2])

    # Measure
    qc.measure(qr[0], cr[0])
    qc.measure(qr[1], cr[1])
    qc.measure(qr[2], cr[2])
    qc.measure(qr[3], cr[3])

    return simulate(qc, 1000)


def three_qubit_circuit():
    qr = QuantumRegister(3)
    cr = ClassicalRegister(3)
    qc = QuantumCircuit()
    qc.add_register(qr)
    qc.add_register(cr)

    qc.h(qr[0])
    qc.y(qr[1])
    qc.cz(qr[0], qr[1])
    qc.t(qr[2])

    return simulate(qc, 1000)
