from typing import Callable, Literal, Protocol, TypedDict

from configfile import ConfigWrapper
from gcode import GCodeCommand
from mcu import MCU_endstop
from typing_extensions import override

HINT_TIMEOUT: str

type _Pos = list[float]

def run_single_probe(probe: PrinterProbe, gcmd: GCodeCommand) -> None: ...
def calc_probe_z_average(positions: list[_Pos], method: Literal["average", "median"] = "average") -> _Pos: ...

class _ProbeStatus(TypedDict):
    name: str
    last_query: bool | int
    last_z_result: float

class ProbeCommandHelper:
    def __init__(
        self,
        config: ConfigWrapper,
        probe: object,
        query_endstop: Callable[[float], int] | None = None,
    ) -> None: ...
    def get_status(self, eventtime: float) -> _ProbeStatus: ...

class HomingViaProbeHelper:
    def __init__(self, config: ConfigWrapper, mcu_probe: ProbeEndstopWrapper) -> None: ...

class ProbeOffsetsHelper:
    def __init__(self, config: ConfigWrapper) -> None: ...
    def get_offsets(self) -> tuple[float, float, float]: ...

class _ProbeSession(Protocol):
    def run_probe(self, gcmd: GCodeCommand) -> None: ...
    def end_probe_session(self) -> None: ...
    def pull_probed_results(self) -> list[_Pos]: ...

class ProbeSessionHelper(_ProbeSession):
    def __init__(self, config: ConfigWrapper, mcu_probe: ProbeEndstopWrapper) -> None: ...
    def start_probe_session(self, gcmd: GCodeCommand) -> _ProbeSession: ...
    def get_probe_params(self, gcmd: GCodeCommand | None = None) -> dict[str, str | int | float]: ...
    @override
    def run_probe(self, gcmd: GCodeCommand) -> None: ...
    @override
    def pull_probed_results(self) -> list[_Pos]: ...
    @override
    def end_probe_session(self) -> None: ...

class ProbeEndstopWrapper(MCU_endstop, Protocol):
    def multi_probe_begin(self) -> None: ...
    def multi_probe_end(self) -> None: ...
    def probing_move(self, pos: _Pos, speed: float) -> _Pos: ...
    def probe_prepare(self, hmove: float) -> None: ...
    def probe_finish(self, hmove: float) -> None: ...
    @override
    def get_position_endstop(self) -> float: ...

class PrinterProbe(Protocol):
    def get_offsets(self) -> tuple[float, float, float]: ...
    def get_status(self, eventtime: float) -> dict[str, str | int | float]: ...
    # def get_probe_params(self, gcmd: GCodeCommand | None = None) -> dict[str, str | int | float]: ...
    # def start_probe_session(self, gcmd: GCodeCommand) -> _ProbeSession: ...
