from __future__ import annotations

import json
from typing import Any
from uuid import UUID

from qhub.api.quantum import HubQuantumClient
from .iqm_client_sdk.iqm_client.iqm_client import IQMClient, CircuitJob
from .iqm_client_sdk.iqm_client.models import (
    CalibrationSet,
    CircuitBatch,
    CircuitCompilationOptions,
    DynamicQuantumArchitecture,
    QualityMetricSet,
    RunRequest,
    StaticQuantumArchitecture,
)


class _HubIqmClient(IQMClient):
    """Adapter client bridging Kipu Quantum Hub to IQM SDK protocols.

    Inherits from IQMClient but routes calls through Kipu Quantum Hub's backend infrastructure,
    enabling IQMBackend to work within the Kipu Quantum Hub middleware while maintaining IQM SDK compatibility.
    """

    def __init__(self, hub_client: HubQuantumClient, backend_id: str):
        """Initialize the HubIqmClient with a Hub client.

        Args:
            hub_client: An instance of the Hub client to be used for communication with the IQM platform.
            backend_id: The backend ID for the IQM backend.
        """
        self._hub_client = hub_client
        self._backend_id = backend_id
        self._dynamic_quantum_architectures: dict[UUID, DynamicQuantumArchitecture] = {}

    def get_about(self) -> dict[str, Any]:
        """Return information about the IQM client."""
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def get_health(self) -> dict[str, Any]:
        """Return the status of the station control service."""
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def submit_circuits(
            self,
            circuits: CircuitBatch,
            *,
            qubit_mapping: dict[str, str] | None = None,
            calibration_set_id: UUID | None = None,
            shots: int = 1,
            options: CircuitCompilationOptions | None = None,
            use_timeslot: bool = False,
    ) -> CircuitJob:
        """Submit a batch of quantum circuits for execution."""
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def create_run_request(
            self,
            circuits: CircuitBatch,
            *,
            qubit_mapping: dict[str, str] | None = None,
            calibration_set_id: UUID | None = None,
            shots: int = 1,
            options: CircuitCompilationOptions | None = None,
    ) -> RunRequest:
        """Create a run request for executing circuits without sending it to the server."""
        return super().create_run_request(
            circuits=circuits,
            qubit_mapping=qubit_mapping,
            calibration_set_id=calibration_set_id,
            shots=shots,
            options=options,
        )

    def submit_run_request(self, run_request: RunRequest, use_timeslot: bool = False) -> CircuitJob:
        """Submit a run request for execution on a quantum computer.

        Args:
            run_request: Run request to be submitted for execution.
            use_timeslot: Submits the job to the timeslot queue if set to ``True``.

        Returns:
            CircuitJob object containing the ID for the created job.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def get_job(self, job_id: UUID) -> CircuitJob:
        """Query the status and results of a submitted job.

        Args:
            job_id: ID of the job to query.

        Returns:
            Status of the job, can be used to query the results if the job has finished.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def cancel_job(self, job_id: UUID) -> None:
        """Cancel a job that was submitted for execution.

        Args:
            job_id: ID of the job to be canceled.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def delete_job(self, job_id: UUID) -> None:
        """Delete a job.

        Args:
            job_id: ID of the job to be deleted.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def get_job_measurement_counts(self, job_id: UUID) -> Any:
        """Query the measurement counts of an executed job.

        Args:
            job_id: ID of the job to query.

        Returns:
            For each circuit in the batch, measurement results in histogram representation.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def get_job_measurements(self, job_id: UUID) -> Any:
        """Query the measurement results of an executed job.

        Args:
            job_id: ID of the job to query.

        Returns:
            For each circuit in the batch, the measurement results.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def get_calibration_quality_metrics(self, calibration_set_id: UUID | None = None) -> Any:
        """Retrieve the given calibration set and related quality metrics from the server.

        Args:
            calibration_set_id: ID of the calibration set to retrieve.
                If ``None``, the current default calibration set is retrieved.

        Returns:
            Requested calibration set and related quality metrics in a searchable structure.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def get_static_quantum_architecture(self) -> StaticQuantumArchitecture:
        """Retrieve the static quantum architecture (SQA) from the server.

        Returns:
            Static quantum architecture of the server.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def get_quality_metric_set(self, calibration_set_id: UUID | None = None) -> QualityMetricSet:
        """Retrieve the latest quality metric set for the given calibration set from the server.

        Args:
            calibration_set_id: ID of the calibration set for which the quality metrics are returned.
                If ``None``, the current default calibration set is used.

        Returns:
            Requested quality metric set.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def get_calibration_set(self, calibration_set_id: UUID | None = None) -> CalibrationSet:
        """Retrieve the given calibration set from the server.

        Args:
            calibration_set_id: ID of the calibration set to retrieve.
                If ``None``, the current default calibration set is retrieved.

        Returns:
            Requested calibration set.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def get_dynamic_quantum_architecture(self, calibration_set_id: UUID | None = None) -> DynamicQuantumArchitecture:
        """Retrieve the dynamic quantum architecture (DQA) for the given calibration set from the server.

        Args:
            calibration_set_id: ID of the calibration set for which the DQA is retrieved.
                If ``None``, use current default calibration set on the server.

        Returns:
            Dynamic quantum architecture corresponding to the given calibration set.
        """
        config = self._hub_client.backends.get_backend_config(self._backend_id)
        return DynamicQuantumArchitecture.model_validate_json(json.dumps(config))

    def get_feedback_groups(self) -> tuple[frozenset[str], ...]:
        """Retrieve groups of qubits that can receive real-time feedback signals from each other.

        Returns:
            Feedback groups. Within a group, any qubit can receive real-time feedback from any other qubit in
                the same group. A qubit can belong to multiple groups.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")

    def _get_calibration_quality_metrics(self, calibration_set_id: UUID | None = None) -> Any:
        """Internal method to retrieve calibration quality metrics.

        Args:
            calibration_set_id: ID of the calibration set to retrieve metrics for.
                If ``None``, the current default calibration set is used.

        Returns:
            Calibration quality metrics.
        """
        raise NotImplementedError("Not implemented in HubIqmClient.")
