"""
Kipu Quantum Hub Session Runtime Client

This module provides a wrapper that bridges IBM Qiskit Runtime Session API calls
to Kipu Quantum Hub client session methods.
"""

import datetime as dt
from typing import Optional, Dict, Any

from qhub.api.quantum import HubQuantumClient


class RuntimeSessionClientAdapter:
    """Session Runtime Client wrapper for Kipu Quantum Hub integration."""

    def __init__(self, hub_client: HubQuantumClient):
        self._hub_client = hub_client

    @staticmethod
    def _convert_usage_time_to_seconds(usage_time_millis: Optional[int]) -> Optional[float]:
        return usage_time_millis / 1000.0 if usage_time_millis is not None else None

    @staticmethod
    def _to_iso_string(value: Optional[dt.datetime]) -> Optional[str]:
        if value is None:
            return None
        return value.isoformat().replace('+00:00', 'Z')

    def create_session(self, backend,
                       instance: Optional[str] = None,
                       max_time: Optional[int] = None,
                       channel: Optional[str] = None,
                       session_mode: Optional[str] = None,
                       **kwargs) -> Dict[str, Any]:
        """Create a session using IBM Qiskit Runtime API format."""

        backend_name = backend.name if hasattr(backend, 'name') else str(backend)

        if session_mode == "dedicated":
            mode = "dedicated"
        elif session_mode == "batch":
            mode = "batch"
        elif session_mode is None:
            mode = "dedicated"
        else:
            raise ValueError(f"Invalid session mode: {session_mode}. Must be 'dedicated' or 'batch'")

        session_response = self._hub_client.sessions.create_session(
            backend_id=backend_name,
            provider="IBM",
            mode=mode,
            ttl=max_time,
            metadata=kwargs.get('metadata'),
        )

        return {
            'id': session_response.id,
            'backend_name': backend_name,
            'state': self._convert_status_to_ibm(session_response.status),
            'mode': session_response.mode,
            'created_at': session_response.created_at
        }

    def session_details(self, session_id: str) -> Dict[str, Any]:
        """Get session details using IBM Qiskit Runtime API format."""

        session_response = self._hub_client.sessions.get_session(session_id)

        def get_metadata(key: str):
            return session_response.metadata.get(key) if session_response.metadata else None

        usage_time_seconds = self._convert_usage_time_to_seconds(session_response.usage_time_millis)

        closed_statuses = {"CLOSED", "UNKNOWN", "DRAINING"}

        return {
            "id": session_response.id,
            "ibm_id": session_response.provider_id,
            "backend_name": session_response.backend_id,
            "max_ttl": get_metadata("max_ttl"),
            "active_ttl": get_metadata("active_ttl"),
            "interactive_ttl": get_metadata("interactive_ttl"),
            "state": self._convert_status_to_ibm(session_response.status),
            "accepting_jobs": session_response.status not in closed_statuses,
            "last_job_started": get_metadata("last_job_started"),
            "last_job_completed": get_metadata("last_job_completed"),
            "started_at": session_response.created_at,
            "closed_at": self._to_iso_string(session_response.closed_at),
            "activated_at": self._to_iso_string(session_response.started_at),
            "mode": session_response.mode,
            "elapsed_time": usage_time_seconds
        }

    def close_session(self, session_id: str) -> None:
        self._hub_client.sessions.close_session(session_id)

    def cancel_session(self, session_id: str) -> None:
        # qhub-api uses update_session_state to cancel
        self._hub_client.sessions.update_session_state(session_id, accept_jobs=False)

    def _convert_status_to_ibm(self, hub_status: str) -> str:
        """Convert Kipu Quantum Hub session status string to IBM format."""
        status_mapping = {
            "OPEN": 'open',
            "ACTIVE": 'active',
            "INACTIVE": 'inactive',
            "CLOSED": 'closed',
            "DRAINING": 'active',
        }
        return status_mapping.get(hub_status, (hub_status or "unknown").lower())
