from typing import Optional, Union, TYPE_CHECKING

from qhub.api.quantum import HubQuantumClient, Job as JobModel
from qhub.quantum.sdk.backend import HubBackend
from qhub.quantum.sdk.job import JobRequest

if TYPE_CHECKING:
    from qhub.quantum.sdk.qiskit.provider import HubQiskitProvider
from qhub.quantum.sdk.qiskit.job import HubQiskitJob
from qhub.quantum.sdk.qiskit.hub_qiskit_runtime_job import HubRuntimeJobV2
from qhub.quantum.sdk.qiskit.providers.aws.aws_qiskit_job import HubAwsQiskitJob
from qhub.quantum.sdk.qiskit.providers.azure.azure_qiskit_job import HubAzureQiskitJob
from qhub.quantum.sdk.qiskit.providers.qudora.qudora_sim_job import HubQudoraQiskitJob
from qhub.quantum.sdk.qiskit.providers.iqm.iqm_qiskit_job import HubIqmQiskitJob


class HubQiskitJobFactory:
    @staticmethod
    def create_job(backend: Optional[HubBackend], job_id: Optional[str] = None,
                   job_details: Optional[Union[JobModel, JobRequest]] = None,
                   hub_client: Optional[HubQuantumClient] = None,
                   provider: Optional["HubQiskitProvider"] = None) -> HubQiskitJob:

        provider_str = HubQiskitJobFactory._get_provider(backend, job_details)

        if not provider_str:
            raise ValueError("Provider information is missing. Either 'backend' or 'job_details' with the 'provider' attribute must be specified.")

        if provider_str == "AWS":
            return HubAwsQiskitJob(backend, job_id, job_details, hub_client)
        elif provider_str == "AZURE":
            return HubAzureQiskitJob(backend, job_id, job_details, hub_client)
        elif provider_str == "QUDORA":
            return HubQudoraQiskitJob(backend, job_id, job_details, hub_client)
        elif provider_str == "IQM":
            return HubIqmQiskitJob(backend, job_id, job_details, hub_client)
        elif provider_str == "IBM":
            return HubRuntimeJobV2(backend=backend, job_id=job_id, job_details=job_details, hub_client=hub_client, provider=provider)
        else:
            return HubQiskitJob(backend, job_id, job_details, hub_client)

    @staticmethod
    def _get_provider(backend, job_details):
        if backend:
            provider = backend.backend_info.provider
        else:
            provider = job_details.provider if job_details else None
        return provider
