from dell_runtime import DellRuntimeProvider
from qiskit import QuantumCircuit
import logging
import requests
import time
import os

RUNTIME_PROGRAM = """
# This code is part of qiskit-runtime.
#
# (C) Copyright IBM 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
from qiskit.compiler import transpile, schedule


def main(
    backend,
    user_messenger,
    circuits,
    **kwargs,
):
    circuits = transpile(
        circuits,
    )
    
    user_messenger.publish({'results': 'intermittently'}, final=False)

    if not isinstance(circuits, list):
        circuits = [circuits]

    # Compute raw results using either simulator or QPU backend.
    result = backend.run(circuits, **kwargs).result()

    user_messenger.publish(result.to_dict(), final=True)
"""

RUNTIME_PROGRAM_METADATA = {
    "max_execution_time": 600,
    "description": "Qiskit test program"
}

PROGRAM_PREFIX = 'qiskit-test'
REMOTE_RUNTIME = os.getenv("SERVER_URL") 

logging.basicConfig(level=logging.DEBUG)

provider = DellRuntimeProvider()

program_id = provider.runtime.upload_program(RUNTIME_PROGRAM, metadata=RUNTIME_PROGRAM_METADATA)
print(f"PROGRAM ID: {program_id}")
programs = provider.runtime.pprint_programs(refresh=True)

provider.runtime.update_program(program_id, description="IBM/Dell Updated Qiskit Runtime Program")
programs = provider.runtime.pprint_programs(refresh=True)

qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])

program_inputs = {
    'circuits': qc,
}

job = provider.runtime.run(program_id, options=None, inputs=program_inputs)

results = job.result(timeout=60)
print(results)

def callback_function(msg):
    print(f'******************\n\n\nFrom Callback Function: {msg}\n\n\n******************')

job = provider.runtime.run(program_id, inputs=program_inputs, options=None, callback=callback_function)

program_inputs['backend_name'] = 'emulator'
job = provider.runtime.run(program_id, inputs=program_inputs, options=None, callback=callback_function)

from dell_runtime import DellRuntimeProvider
from qiskit import QuantumCircuit
import logging
import requests
import time
import os

RUNTIME_PROGRAM = """
# This code is part of qiskit-runtime.
#
# (C) Copyright IBM 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
from qiskit.compiler import transpile, schedule


def main(
    backend,
    user_messenger,
    circuits,
    **kwargs,
):
    circuits = transpile(
        circuits,
    )
    
    user_messenger.publish({'results': 'intermittently'}, final=False)

    if not isinstance(circuits, list):
        circuits = [circuits]

    # Compute raw results
    result = backend.run(circuits, **kwargs).result()

    user_messenger.publish(result.to_dict(), final=True)
"""

RUNTIME_PROGRAM_METADATA = {
    "max_execution_time": 600,
    "description": "Qiskit test program"
}

PROGRAM_PREFIX = 'qiskit-test'
REMOTE_RUNTIME = os.getenv("SERVER_URL") 

logging.basicConfig(level=logging.DEBUG)

provider = DellRuntimeProvider()
provider.remote(REMOTE_RUNTIME)

text_program_id = provider.runtime.upload_program(RUNTIME_PROGRAM, metadata=RUNTIME_PROGRAM_METADATA)
print(f"PROGRAM ID: {text_program_id}")

programs = provider.runtime.pprint_programs(refresh=True)
provider.runtime.update_program(text_program_id, description="IBM/Dell Updated Qiskit Runtime Program")
programs = provider.runtime.pprint_programs(refresh=True)

file_program_id = provider.runtime.upload_program("qka.py", description="File Upload to Orchestrator")
dir_program_id = provider.runtime.upload_program("./qkad", description="Directory Upload to Orchestrator")

provider.runtime.pprint_programs(refresh=True)

qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])

program_inputs = {
    'circuits': qc,
}

job = provider.runtime.run(text_program_id, options=None, inputs=program_inputs)

results = job.result(timeout=60)
print(results)

program_inputs['backend_name'] = 'emulator'
job = provider.runtime.run(text_program_id, inputs=program_inputs, options=None, callback=callback_function)
results = job.result(timeout=600)
print(results)

from dell_runtime import DellRuntimeProvider
from qiskit import QuantumCircuit
import pandas as pd
from time import sleep
import os
import base64
import shutil
import json

provider = DellRuntimeProvider()

RUNTIME_PROGRAM_METADATA = {
    "max_execution_time": 600,
    "description": "Qiskit test program"
}

provider.remote(os.getenv("SERVER_URL"))
here = os.path.dirname(os.path.realpath(__file__))

program_id = provider.runtime.upload_program(here + "../examples/programs/qkad", metadata=RUNTIME_PROGRAM_METADATA)

job = provider.runtime.run(program_id, options=None, inputs={})

res = job.result(timeout=1000)
print(res)

from qiskit.opflow import Z, I
from qiskit.circuit.library import EfficientSU2
import numpy as np
from qiskit.algorithms.optimizers import SPSA
from dell_runtime import DellRuntimeProvider
import os
from time import sleep
from datetime import datetime, timedelta

num_qubits = 4
hamiltonian = (Z ^ Z) ^ (I ^ (num_qubits - 2))
target_energy = -1


# the rotation gates are chosen randomly, so we set a seed for reproducibility
ansatz = EfficientSU2(num_qubits, reps=1, entanglement='linear', insert_barriers=True)
# ansatz.draw('mpl', style='iqx')

optimizer = SPSA(maxiter=50)

np.random.seed(10)  # seed for reproducibility
initial_point = np.random.random(ansatz.num_parameters)
intermediate_info = {
    'nfev': [],
    'parameters': [],
    'energy': [],
    'stddev': []
}

timestamps = []

def raw_callback(*args):
    (nfev, parameters, energy, stddev) = args[0]
    intermediate_info['nfev'].append(nfev)
    intermediate_info['parameters'].append(parameters)
    intermediate_info['energy'].append(energy)
    intermediate_info['stddev'].append(stddev)
    
vqe_inputs = {
    'ansatz': ansatz,
    'operator': hamiltonian,
    'optimizer': {'name': 'SPSA', 'maxiter': 15},  # let's only do a few iterations!
    'initial_point': initial_point,
    'measurement_error_mitigation': True,
    'shots': 1024,
    # Include this parameter to use the snapshot instruction and return the ideal outcome
    # that has no shot noise and avoids using the statevector simulator.
    # 'include_custom': True
}

provider = DellRuntimeProvider()
provider.remote(os.getenv("SERVER_URL"))
program_id = provider.runtime.upload_program("vqe.py", description="Variational Quantum Eigensolver Program")

job = provider.runtime.run(
    program_id=program_id,
    inputs=vqe_inputs,
    options=None,
    callback=raw_callback
)

print('Job ID:', job.job_id)

result = job.result()
while not result:
    print('no result yet.')
    sleep(0.5)
    result = job.result()

print(f"Intermediate Results: {intermediate_info}")
print(f'Reached {result["optimal_value"]} after {result["optimizer_evals"]} evaluations.')
print('Available keys:', list(result.keys()))