"""Type stubs for hiq Python bindings."""

from typing import List, Optional, Union

class QubitId:
    """Unique identifier for a qubit within a circuit."""

    @property
    def index(self) -> int: ...
    def __init__(self, index: int) -> None: ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...
    def __hash__(self) -> int: ...
    def __eq__(self, other: QubitId) -> bool: ...
    def __int__(self) -> int: ...

class ClbitId:
    """Unique identifier for a classical bit within a circuit."""

    @property
    def index(self) -> int: ...
    def __init__(self, index: int) -> None: ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...
    def __hash__(self) -> int: ...
    def __eq__(self, other: ClbitId) -> bool: ...
    def __int__(self) -> int: ...

QubitArg = Union[QubitId, int]
ClbitArg = Union[ClbitId, int]

class Circuit:
    """A quantum circuit."""

    @property
    def name(self) -> str: ...
    @property
    def num_qubits(self) -> int: ...
    @property
    def num_clbits(self) -> int: ...
    def __init__(
        self, name: str, num_qubits: int = 0, num_clbits: int = 0
    ) -> None: ...
    def depth(self) -> int: ...
    def add_qubit(self) -> QubitId: ...
    def add_clbit(self) -> ClbitId: ...
    def add_qreg(self, name: str, size: int) -> List[QubitId]: ...
    def add_creg(self, name: str, size: int) -> List[ClbitId]: ...

    # Single-qubit gates
    def h(self, qubit: QubitArg) -> Circuit: ...
    def x(self, qubit: QubitArg) -> Circuit: ...
    def y(self, qubit: QubitArg) -> Circuit: ...
    def z(self, qubit: QubitArg) -> Circuit: ...
    def s(self, qubit: QubitArg) -> Circuit: ...
    def sdg(self, qubit: QubitArg) -> Circuit: ...
    def t(self, qubit: QubitArg) -> Circuit: ...
    def tdg(self, qubit: QubitArg) -> Circuit: ...
    def sx(self, qubit: QubitArg) -> Circuit: ...
    def rx(self, theta: float, qubit: QubitArg) -> Circuit: ...
    def ry(self, theta: float, qubit: QubitArg) -> Circuit: ...
    def rz(self, theta: float, qubit: QubitArg) -> Circuit: ...
    def p(self, theta: float, qubit: QubitArg) -> Circuit: ...
    def u(
        self, theta: float, phi: float, lam: float, qubit: QubitArg
    ) -> Circuit: ...

    # Two-qubit gates
    def cx(self, control: QubitArg, target: QubitArg) -> Circuit: ...
    def cy(self, control: QubitArg, target: QubitArg) -> Circuit: ...
    def cz(self, control: QubitArg, target: QubitArg) -> Circuit: ...
    def swap(self, q1: QubitArg, q2: QubitArg) -> Circuit: ...
    def iswap(self, q1: QubitArg, q2: QubitArg) -> Circuit: ...
    def crz(
        self, theta: float, control: QubitArg, target: QubitArg
    ) -> Circuit: ...
    def cp(
        self, theta: float, control: QubitArg, target: QubitArg
    ) -> Circuit: ...

    # IQM native gates
    def prx(self, theta: float, phi: float, qubit: QubitArg) -> Circuit: ...

    # Three-qubit gates
    def ccx(self, c1: QubitArg, c2: QubitArg, target: QubitArg) -> Circuit: ...
    def cswap(
        self, control: QubitArg, t1: QubitArg, t2: QubitArg
    ) -> Circuit: ...

    # Other operations
    def measure(self, qubit: QubitArg, clbit: ClbitArg) -> Circuit: ...
    def measure_all(self) -> Circuit: ...
    def reset(self, qubit: QubitArg) -> Circuit: ...
    def barrier_all(self) -> Circuit: ...
    def delay(self, qubit: QubitArg, duration: int) -> Circuit: ...

    # Pre-built circuits
    @staticmethod
    def bell() -> Circuit: ...
    @staticmethod
    def ghz(n: int) -> Circuit: ...
    @staticmethod
    def qft(n: int) -> Circuit: ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...

class Layout:
    """A mapping from logical qubits to physical qubits."""

    def __init__(self) -> None: ...
    @staticmethod
    def trivial(num_qubits: int) -> Layout: ...
    def add(self, logical: int, physical: int) -> None: ...
    def get_physical(self, logical: int) -> Optional[int]: ...
    def get_logical(self, physical: int) -> Optional[QubitId]: ...
    def swap(self, p1: int, p2: int) -> None: ...
    def __len__(self) -> int: ...
    def __repr__(self) -> str: ...

class CouplingMap:
    """Target device coupling map."""

    @property
    def num_qubits(self) -> int: ...
    def __init__(self, num_qubits: int) -> None: ...
    def add_edge(self, q1: int, q2: int) -> None: ...
    def is_connected(self, q1: int, q2: int) -> bool: ...
    def edges(self) -> List[tuple[int, int]]: ...
    def distance(self, from_: int, to: int) -> Optional[int]: ...
    @staticmethod
    def linear(n: int) -> CouplingMap: ...
    @staticmethod
    def full(n: int) -> CouplingMap: ...
    @staticmethod
    def star(n: int) -> CouplingMap: ...
    def __repr__(self) -> str: ...

class BasisGates:
    """Basis gates for the target device."""

    def __init__(self, gates: List[str]) -> None: ...
    def contains(self, gate: str) -> bool: ...
    def gates(self) -> List[str]: ...
    @staticmethod
    def iqm() -> BasisGates: ...
    @staticmethod
    def ibm() -> BasisGates: ...
    @staticmethod
    def universal() -> BasisGates: ...
    def __repr__(self) -> str: ...

class PropertySet:
    """Properties shared between compilation passes."""

    def __init__(self) -> None: ...
    def set_layout(self, layout: Layout) -> None: ...
    def get_layout(self) -> Optional[Layout]: ...
    def set_coupling_map(self, coupling_map: CouplingMap) -> None: ...
    def get_coupling_map(self) -> Optional[CouplingMap]: ...
    def set_basis_gates(self, basis_gates: BasisGates) -> None: ...
    def get_basis_gates(self) -> Optional[BasisGates]: ...
    def with_target(
        self, coupling_map: CouplingMap, basis_gates: BasisGates
    ) -> PropertySet: ...
    def __repr__(self) -> str: ...

def from_qasm(qasm: str) -> Circuit:
    """Parse an OpenQASM 3 string into a Circuit."""
    ...

def to_qasm(circuit: Circuit) -> str:
    """Emit a Circuit as an OpenQASM 3 string."""
    ...
