import sys
import os
current_dir = os.getcwd()
sys.path.append(os.path.dirname(os.path.abspath(current_dir)))
from Grover.grover_num_list_cirq import find_num, find_num_list
from Backend.fake_backend import FakeBackend
from Backend.backend import Backend
from Backend.ibm_backend import IBM_backend

from Result.result import ResultData

from qiskit.visualization import plot_histogram, plot_coupling_map
from backend_operation import run_simulator, get_transpiled_circuits_of_circuit, get_fake_backend_list,get_unitary, get_fake_backend, get_fake_backend_list
from qiskit import transpile
import qiskit.providers.fake_provider
from qiskit_ibm_provider import IBMProvider
from qiskit.transpiler.passes import RemoveBarriers
from qiskit_aer import AerSimulator, Aer

from itertools import permutations

# Sample of Find Number Grover Circuit
find_num_in_world_obj =  find_num()
find_num_in_world_obj.build_iteration(winner_num_list=[0], circuit_nqubits=3, block_diagram=False)
find_num_in_world_obj.create_grover(num_solutions=1, prep_value=[], block_diagram=False)
cur_experiments = find_num_in_world_obj.measure_qc
print(f"Number of Grover circuits : {len(cur_experiments)}")
cur_experiments[0].draw('mpl')

backend = qiskit.providers.fake_provider.GenericBackendV2(num_qubits=3)
backend.coupling_map.draw()

# Transpile the ideal circuit to a circuit that can be directly executed by the backend
transpiled_circuit = transpile(cur_experiments[0], backend, optimization_level=0)
transpiled_circuit.draw('mpl')


transpiled_circuit = transpile(cur_experiments[0], backend, optimization_level=3)
transpiled_circuit.draw('mpl')

find_num_obj = find_num()
num_qubits = 3
qc_find_num_list = []

for value in range(2**num_qubits):
    find_num_obj.build_iteration(winner_num_list=[value], circuit_nqubits=num_qubits, block_diagram=False)
    find_num_obj.create_grover(num_solutions=1, prep_value=[], block_diagram=False)
    qc_find_num_list.append(find_num_obj.measure_qc[0])

generic_backend = Backend(num_qubits)
backend_names = FakeBackend.get_ibm_fake_backend_names_with_limit(num_qubits)
fake_auckland_backend = FakeBackend.get_ibm_fake_backend('fake_auckland')
print(f"Fake Auckland number of qubits = {fake_auckland_backend.num_qubits}")

fake_backend_name = 'fake_auckland'
fake_backend = FakeBackend(fake_backend_name)

position_layout = permutations(range(fake_backend.get_backend_qubits()), num_qubits)

position_layout = permutations(range(num_qubits), num_qubits)

qc_find_num_list_without_barriar = [RemoveBarriers()(qc) for qc in qc_find_num_list]

# Add the Generic Aer Full Connectivity
qc_transpiled_list = [
    generic_backend.transpile_save_param(qc=qc, optimization_level=0, initial_layout=None, seed_transpiler=None, input_search = index)
    for index, qc in enumerate(qc_find_num_list_without_barriar)
]
qc_transpiled_list = qc_transpiled_list + [
    generic_backend.transpile_save_param(qc=qc, optimization_level=3, initial_layout=None, seed_transpiler=None, input_search = index)
    for index, qc in enumerate(qc_find_num_list_without_barriar)
]
position_layout = list(position_layout)
# Add the fake backend
for layout in [None] + position_layout:
    qc_transpiled_list = qc_transpiled_list + [
        fake_backend.transpile_save_param(qc=qc, optimization_level=0, initial_layout=layout, seed_transpiler=None, input_search = index)
        for index, qc in enumerate(qc_find_num_list_without_barriar)
    ]
    qc_transpiled_list = qc_transpiled_list + [
        fake_backend.transpile_save_param(qc=qc, optimization_level=3, initial_layout=layout, seed_transpiler=None, input_search = index)
        for index, qc in enumerate(qc_find_num_list_without_barriar)
    ]

# Sample that we entered an input value to the result parameters to save
qc_transpiled_list[60].backend_name

qc_res  = [
    qc_param.backend.run(qc_param.transpiled_qc,shots=1024)
    for qc_param in qc_transpiled_list
]

len(qc_res)

result = ResultData(qc_res[60])

result.job

result.to_dict()

result.to_dict().keys()

result.get_result_time_taken(0)

result.to_dict()['time_taken']

result.to_dict()['results'][0].keys()

result.to_dict()['results'][0]['time_taken']

result.get_counts()

result.get_data()

result.to_dict().keys()

result.to_dict()['results'][0].keys()

result.to_dict()['results'][0]['time_taken']

result.to_dict()['results'][0]['header']

result.to_dict()['results'][0]['data']

result.to_dict()['results'][0]['metadata']